X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fusers.cpp;h=0dfe54f65d2ece1a7c43c2bfe6a1d8fac73493a1;hb=94e530b1cb59ba806dfb497a1e27d44e5d2e02d5;hp=19e4925b60f5209f90f41e414d57a50a5e28b467;hpb=5db1d322be106c8462dc691072f9415dc0766ed4;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/users.cpp b/src/users.cpp index 19e4925b6..0dfe54f65 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -21,10 +21,17 @@ #include "bancache.h" #include "commands/cmd_whowas.h" -static unsigned long already_sent[MAX_DESCRIPTORS] = {0}; +static unsigned long* already_sent = NULL; + + +void InitializeAlreadySent(SocketEngine* SE) +{ + already_sent = new unsigned long[SE->GetMaxFds()]; + memset(already_sent, 0, sizeof(already_sent)); +} /* XXX: Used for speeding up WriteCommon operations */ -unsigned long uniq_id = 0; +unsigned long uniq_id = 1; std::string User::ProcessNoticeMasks(const char *sm) { @@ -73,6 +80,9 @@ std::string User::ProcessNoticeMasks(const char *sm) output += *c; } } + else + this->WriteNumeric(501, "%s %c :is unknown snomask char to me", this->nick, *c); + oldadding = adding; break; } @@ -177,11 +187,11 @@ User::User(InspIRCd* Instance, const std::string &uid) : ServerInstance(Instance *password = *nick = *ident = *host = *dhost = *fullname = *awaymsg = *oper = *uuid = 0; server = (char*)Instance->FindServerNamePtr(Instance->Config->ServerName); reset_due = ServerInstance->Time(); - age = ServerInstance->Time(true); + age = ServerInstance->Time(); Penalty = 0; lines_in = lastping = signon = idle_lastmsg = nping = registered = 0; ChannelCount = timeout = bytes_in = bytes_out = cmds_in = cmds_out = 0; - OverPenalty = ExemptFromPenalty = quitting = exempt = haspassed = dns_done = false; + quietquit = OverPenalty = ExemptFromPenalty = quitting = exempt = haspassed = dns_done = false; fd = -1; recvq.clear(); sendq.clear(); @@ -190,6 +200,9 @@ User::User(InspIRCd* Instance, const std::string &uid) : ServerInstance(Instance Visibility = NULL; ip = NULL; MyClass = NULL; + io = NULL; + AllowedUserModes = NULL; + AllowedChanModes = NULL; AllowedOperCommands = NULL; chans.clear(); invites.clear(); @@ -218,7 +231,7 @@ User::~User() if (this->MyClass) { this->MyClass->RefCount--; - ServerInstance->Logs->Log("USERS", DEBUG, "User destructor -- connect refcount now: %u", this->MyClass->RefCount); + ServerInstance->Logs->Log("USERS", DEBUG, "User destructor -- connect refcount now: %lu", this->MyClass->RefCount); } if (this->AllowedOperCommands) { @@ -226,6 +239,18 @@ User::~User() AllowedOperCommands = NULL; } + if (this->AllowedUserModes) + { + delete[] AllowedUserModes; + AllowedUserModes = NULL; + } + + if (this->AllowedChanModes) + { + delete[] AllowedChanModes; + AllowedChanModes = NULL; + } + this->InvalidateCache(); this->DecrementModes(); @@ -290,8 +315,11 @@ char* User::MakeHostIP() void User::CloseSocket() { - ServerInstance->SE->Shutdown(this, 2); - ServerInstance->SE->Close(this); + if (this->fd > -1) + { + ServerInstance->SE->Shutdown(this, 2); + ServerInstance->SE->Close(this); + } } char* User::GetFullHost() @@ -434,6 +462,21 @@ void User::RemoveInvite(const irc::string &channel) } } +bool User::HasModePermission(unsigned char mode, ModeType type) +{ + if (!IS_LOCAL(this)) + return true; + + if (!IS_OPER(this)) + return false; + + if (!AllowedUserModes || !AllowedChanModes) + return false; + + return ((type == MODETYPE_USER ? AllowedUserModes : AllowedChanModes))[(mode - 'A')]; + +} + bool User::HasPermission(const std::string &command) { /* @@ -487,7 +530,7 @@ bool User::AddBuffer(std::string a) if (this->MyClass && (recvq.length() > this->MyClass->GetRecvqMax())) { this->SetWriteError("RecvQ exceeded"); - ServerInstance->SNO->WriteToSnoMask('A', "User %s RecvQ of %d exceeds connect class maximum of %d",this->nick,recvq.length(),this->MyClass->GetRecvqMax()); + ServerInstance->SNO->WriteToSnoMask('A', "User %s RecvQ of %lu exceeds connect class maximum of %lu",this->nick,(unsigned long int)recvq.length(),this->MyClass->GetRecvqMax()); return false; } @@ -564,7 +607,7 @@ void User::AddWriteBuf(const std::string &data) * to repeatedly add the text to the sendq! */ this->SetWriteError("SendQ exceeded"); - ServerInstance->SNO->WriteToSnoMask('A', "User %s SendQ of %d exceeds connect class maximum of %d",this->nick,sendq.length() + data.length(),this->MyClass->GetSendqMax()); + ServerInstance->SNO->WriteToSnoMask('A', "User %s SendQ of %lu exceeds connect class maximum of %lu",this->nick,(unsigned long int)sendq.length() + data.length(),this->MyClass->GetSendqMax()); return; } @@ -666,6 +709,15 @@ void User::Oper(const std::string &opertype, const std::string &opername) else AllowedOperCommands = new std::map; + if (!AllowedChanModes) + AllowedChanModes = new bool[64]; + + if (!AllowedUserModes) + AllowedUserModes = new bool[64]; + + memset(AllowedUserModes, 0, 64); + memset(AllowedChanModes, 0, 64); + char* Classes = strdup(iter_opertype->second); char* myclass = strtok_r(Classes," ",&savept); while (myclass) @@ -673,7 +725,7 @@ void User::Oper(const std::string &opertype, const std::string &opername) operclass_t::iterator iter_operclass = ServerInstance->Config->operclass.find(myclass); if (iter_operclass != ServerInstance->Config->operclass.end()) { - char* CommandList = strdup(iter_operclass->second); + char* CommandList = strdup(iter_operclass->second.commandlist); mycmd = strtok_r(CommandList," ",&savept2); while (mycmd) { @@ -681,6 +733,29 @@ void User::Oper(const std::string &opertype, const std::string &opername) mycmd = strtok_r(NULL," ",&savept2); } free(CommandList); + this->AllowedUserModes['o' - 'A'] = true; // Call me paranoid if you want. + for (unsigned char* c = (unsigned char*)iter_operclass->second.umodelist; *c; ++c) + { + if (*c == '*') + { + memset(this->AllowedUserModes, (int)(true), 64); + } + else + { + this->AllowedUserModes[*c - 'A'] = true; + } + } + for (unsigned char* c = (unsigned char*)iter_operclass->second.cmodelist; *c; ++c) + { + if (*c == '*') + { + memset(this->AllowedChanModes, (int)(true), 64); + } + else + { + this->AllowedChanModes[*c - 'A'] = true; + } + } } myclass = strtok_r(NULL," ",&savept); } @@ -692,7 +767,7 @@ void User::Oper(const std::string &opertype, const std::string &opername) catch (...) { - ServerInstance->Log(DEBUG,"Exception in User::Oper()"); + ServerInstance->Logs->Log("OPER", DEBUG,"Exception in User::Oper()"); } } @@ -700,11 +775,27 @@ void User::UnOper() { if (IS_OPER(this)) { - // unset their oper type (what IS_OPER checks), and remove +o + /* Remove all oper only modes from the user when the deoper - Bug #466*/ + std::string moderemove("-"); + + for (unsigned char letter = 'A'; letter <= 'z'; letter++) + { + if (letter != 'o') + { + ModeHandler* mh = ServerInstance->Modes->FindMode(letter, MODETYPE_USER); + if (mh && mh->NeedsOper()) + moderemove += letter; + } + } + + const char* parameters[] = { this->nick, moderemove.c_str() }; + ServerInstance->Parser->CallHandler("MODE", parameters, 2, this); + + /* unset their oper type (what IS_OPER checks), and remove +o */ *this->oper = 0; this->modes[UM_OPERATOR] = 0; - // remove the user from the oper list. Will remove multiple entries as a safeguard against bug #404 + /* remove the user from the oper list. Will remove multiple entries as a safeguard against bug #404 */ ServerInstance->Users->all_opers.remove(this); if (AllowedOperCommands) @@ -712,6 +803,17 @@ void User::UnOper() delete AllowedOperCommands; AllowedOperCommands = NULL; } + if (AllowedUserModes) + { + delete[] AllowedUserModes; + AllowedUserModes = NULL; + } + if (AllowedChanModes) + { + delete[] AllowedChanModes; + AllowedChanModes = NULL; + } + } } @@ -721,7 +823,12 @@ void User::QuitUser(InspIRCd* Instance, User *user, const std::string &quitreaso user->Write("ERROR :Closing link (%s@%s) [%s]", user->ident, user->host, *operreason ? operreason : quitreason.c_str()); user->quietquit = false; user->quitmsg = quitreason; - user->operquitmsg = operreason; + + if (!*operreason) + user->operquitmsg = quitreason; + else + user->operquitmsg = operreason; + Instance->GlobalCulls.AddItem(user); } @@ -809,14 +916,13 @@ void User::FullConnect() } this->WriteServ("NOTICE Auth :Welcome to \002%s\002!",ServerInstance->Config->Network); - this->WriteServ("001 %s :Welcome to the %s IRC Network %s!%s@%s",this->nick, ServerInstance->Config->Network, this->nick, this->ident, this->host); - this->WriteServ("002 %s :Your host is %s, running version %s",this->nick,ServerInstance->Config->ServerName,VERSION); - this->WriteServ("003 %s :This server was created %s %s", this->nick, __TIME__, __DATE__); - this->WriteServ("004 %s %s %s %s %s %s", this->nick, ServerInstance->Config->ServerName, VERSION, ServerInstance->Modes->UserModeList().c_str(), ServerInstance->Modes->ChannelModeList().c_str(), ServerInstance->Modes->ParaModeList().c_str()); + this->WriteNumeric(001, "%s :Welcome to the %s IRC Network %s!%s@%s",this->nick, ServerInstance->Config->Network, this->nick, this->ident, this->host); + this->WriteNumeric(002, "%s :Your host is %s, running version InspIRCd-1.2",this->nick,ServerInstance->Config->ServerName); + this->WriteNumeric(003, "%s :This server was created %s %s", this->nick, __TIME__, __DATE__); + this->WriteNumeric(004, "%s %s InspIRCd-1.2 %s %s %s", this->nick, ServerInstance->Config->ServerName, ServerInstance->Modes->UserModeList().c_str(), ServerInstance->Modes->ChannelModeList().c_str(), ServerInstance->Modes->ParaModeList().c_str()); ServerInstance->Config->Send005(this); - - this->WriteServ("042 %s %s :your unique ID", this->nick, this->uuid); + this->WriteNumeric(42, "%s %s :your unique ID", this->nick, this->uuid); this->ShowMOTD(); @@ -883,46 +989,35 @@ void User::InvalidateCache() bool User::ForceNickChange(const char* newnick) { - /* - * XXX this makes no sense.. - * why do we do nothing for change on users not REG_ALL? - * why do we trigger events twice for everyone previously (and just them now) - * i think the first if () needs removing totally, or? -- w00t - */ - if (this->registered != REG_ALL) - { - int MOD_RESULT = 0; + int MOD_RESULT = 0; - this->InvalidateCache(); + this->InvalidateCache(); - FOREACH_RESULT(I_OnUserPreNick,OnUserPreNick(this, newnick)); + FOREACH_RESULT(I_OnUserPreNick,OnUserPreNick(this, newnick)); - if (MOD_RESULT) - { - ServerInstance->stats->statsCollisions++; - return false; - } + if (MOD_RESULT) + { + ServerInstance->stats->statsCollisions++; + return false; + } - if (ServerInstance->XLines->MatchesLine("Q",newnick)) - { - ServerInstance->stats->statsCollisions++; - return false; - } + if (ServerInstance->XLines->MatchesLine("Q",newnick)) + { + ServerInstance->stats->statsCollisions++; + return false; } - else + + std::deque dummy; + Command* nickhandler = ServerInstance->Parser->GetHandler("NICK"); + if (nickhandler) // wtfbbq, when would this not be here { - std::deque dummy; - Command* nickhandler = ServerInstance->Parser->GetHandler("NICK"); - if (nickhandler) // wtfbbq, when would this not be here - { - nickhandler->HandleInternal(1, dummy); - bool result = (ServerInstance->Parser->CallHandler("NICK", &newnick, 1, this) == CMD_SUCCESS); - nickhandler->HandleInternal(0, dummy); - return result; - } + nickhandler->HandleInternal(1, dummy); + bool result = (ServerInstance->Parser->CallHandler("NICK", &newnick, 1, this) == CMD_SUCCESS); + nickhandler->HandleInternal(0, dummy); + return result; } - // Unreachable. + // Unreachable, we hope return false; } @@ -953,7 +1048,7 @@ void User::SetSockAddr(int protocol_family, const char* sip, int port) } break; default: - ServerInstance->Log(DEBUG,"Uh oh, I dont know protocol %d to be set on '%s'!", protocol_family, this->nick); + ServerInstance->Logs->Log("USERS",DEBUG,"Uh oh, I dont know protocol %d to be set on '%s'!", protocol_family, this->nick); break; } } @@ -1060,27 +1155,27 @@ void User::Write(std::string text) try { - ServerInstance->Logs->Log("USERIO", DEBUG,"C[%d] O %s", this->GetFd(), text.c_str()); + ServerInstance->Logs->Log("USEROUTPUT", DEBUG,"C[%d] O %s", this->GetFd(), text.c_str()); text.append("\r\n"); } catch (...) { - ServerInstance->Log(DEBUG,"Exception in User::Write() std::string::append"); + ServerInstance->Logs->Log("USEROUTPUT", DEBUG,"Exception in User::Write() std::string::append"); return; } - if (ServerInstance->Config->GetIOHook(this->GetPort())) + if (this->io) { /* XXX: The lack of buffering here is NOT a bug, modules implementing this interface have to * implement their own buffering mechanisms */ try { - ServerInstance->Config->GetIOHook(this->GetPort())->OnRawSocketWrite(this->fd, text.data(), text.length()); + this->io->OnRawSocketWrite(this->fd, text.data(), text.length()); } catch (CoreException& modexcept) { - ServerInstance->Log(DEBUG, "%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason()); + ServerInstance->Logs->Log("USEROUTPUT", DEBUG, "%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason()); } } else @@ -1129,6 +1224,32 @@ void User::WriteServ(const char* text, ...) } +void User::WriteNumeric(unsigned int numeric, const char* text, ...) +{ + va_list argsPtr; + char textbuffer[MAXBUF]; + + va_start(argsPtr, text); + vsnprintf(textbuffer, MAXBUF, text, argsPtr); + va_end(argsPtr); + + this->WriteNumeric(numeric, std::string(textbuffer)); +} + +void User::WriteNumeric(unsigned int numeric, const std::string &text) +{ + char textbuffer[MAXBUF]; + int MOD_RESULT = 0; + + FOREACH_RESULT(I_OnNumeric, OnNumeric(this, numeric, text)); + + if (MOD_RESULT) + return; + + snprintf(textbuffer,MAXBUF,":%s %03u %s",ServerInstance->Config->ServerName, numeric, text.c_str()); + this->Write(std::string(textbuffer)); +} + void User::WriteFrom(User *user, const std::string &text) { char tb[MAXBUF]; @@ -1199,6 +1320,9 @@ void User::WriteCommon(const std::string &text) uniq_id++; + if (!already_sent) + InitializeAlreadySent(ServerInstance->SE); + /* We dont want to be doing this n times, just once */ snprintf(tb,MAXBUF,":%s %s",this->GetFullHost(),text.c_str()); std::string out = tb; @@ -1253,6 +1377,10 @@ void User::WriteCommonQuit(const std::string &normal_text, const std::string &op return; uniq_id++; + + if (!already_sent) + InitializeAlreadySent(ServerInstance->SE); + snprintf(tb1,MAXBUF,":%s QUIT :%s",this->GetFullHost(),normal_text.c_str()); snprintf(tb2,MAXBUF,":%s QUIT :%s",this->GetFullHost(),oper_text.c_str()); std::string out1 = tb1; @@ -1284,6 +1412,10 @@ void User::WriteCommonExcept(const std::string &text) return; uniq_id++; + + if (!already_sent) + InitializeAlreadySent(ServerInstance->SE); + snprintf(tb1,MAXBUF,":%s %s",this->GetFullHost(),text.c_str()); out1 = tb1; @@ -1307,7 +1439,7 @@ void User::WriteCommonExcept(const std::string &text) void User::WriteWallOps(const std::string &text) { - if (!IS_OPER(this) && IS_LOCAL(this)) + if (!IS_LOCAL(this)) return; std::string wallop("WALLOPS :"); @@ -1323,6 +1455,9 @@ void User::WriteWallOps(const std::string &text) void User::WriteWallOps(const char* text, ...) { + if (!IS_LOCAL(this)) + return; + char textbuffer[MAXBUF]; va_list argsPtr; @@ -1414,7 +1549,7 @@ bool User::ChangeDisplayedHost(const char* shost) } if (IS_LOCAL(this)) - this->WriteServ("396 %s %s :is now your displayed host",this->nick,this->dhost); + this->WriteNumeric(396, "%s %s :is now your displayed host",this->nick,this->dhost); return true; } @@ -1445,7 +1580,7 @@ bool User::ChangeIdent(const char* newident) return true; } -void User::SendAll(const char* command, char* text, ...) +void User::SendAll(const char* command, const char* text, ...) { char textbuffer[MAXBUF]; char formatbuffer[MAXBUF]; @@ -1585,7 +1720,7 @@ ConnectClass* User::SetClass(const std::string &explicit_name) /* deny change if change will take class over the limit */ if (found->limit && (found->RefCount + 1 >= found->limit)) { - ServerInstance->Log(DEBUG, "OOPS: Connect class limit (%u) hit, denying", found->limit); + ServerInstance->Logs->Log("USERS", DEBUG, "OOPS: Connect class limit (%lu) hit, denying", found->limit); return this->MyClass; } @@ -1595,12 +1730,12 @@ ConnectClass* User::SetClass(const std::string &explicit_name) if (found == this->MyClass) // no point changing this shit :P return this->MyClass; this->MyClass->RefCount--; - ServerInstance->Log(DEBUG, "Untying user from connect class -- refcount: %u", this->MyClass->RefCount); + ServerInstance->Logs->Log("USERS", DEBUG, "Untying user from connect class -- refcount: %lu", this->MyClass->RefCount); } this->MyClass = found; this->MyClass->RefCount++; - ServerInstance->Log(DEBUG, "User tied to new class -- connect refcount now: %u", this->MyClass->RefCount); + ServerInstance->Logs->Log("USERS", DEBUG, "User tied to new class -- connect refcount now: %lu", this->MyClass->RefCount); } return this->MyClass; @@ -1633,7 +1768,7 @@ void User::PurgeEmptyChannels() } catch (...) { - ServerInstance->Log(DEBUG,"Exception in User::PurgeEmptyChannels to_delete.push_back()"); + ServerInstance->Logs->Log("USERS", DEBUG,"Exception in User::PurgeEmptyChannels to_delete.push_back()"); } } } @@ -1658,31 +1793,31 @@ void User::ShowMOTD() { if (!ServerInstance->Config->MOTD.size()) { - this->WriteServ("422 %s :Message of the day file is missing.",this->nick); + this->WriteNumeric(422, "%s :Message of the day file is missing.",this->nick); return; } - this->WriteServ("375 %s :%s message of the day", this->nick, ServerInstance->Config->ServerName); + this->WriteNumeric(375, "%s :%s message of the day", this->nick, ServerInstance->Config->ServerName); for (file_cache::iterator i = ServerInstance->Config->MOTD.begin(); i != ServerInstance->Config->MOTD.end(); i++) - this->WriteServ("372 %s :- %s",this->nick,i->c_str()); + this->WriteNumeric(372, "%s :- %s",this->nick,i->c_str()); - this->WriteServ("376 %s :End of message of the day.", this->nick); + this->WriteNumeric(376, "%s :End of message of the day.", this->nick); } void User::ShowRULES() { if (!ServerInstance->Config->RULES.size()) { - this->WriteServ("434 %s :RULES File is missing",this->nick); + this->WriteNumeric(434, "%s :RULES File is missing",this->nick); return; } - this->WriteServ("308 %s :- %s Server Rules -",this->nick,ServerInstance->Config->ServerName); + this->WriteNumeric(308, "%s :- %s Server Rules -",this->nick,ServerInstance->Config->ServerName); for (file_cache::iterator i = ServerInstance->Config->RULES.begin(); i != ServerInstance->Config->RULES.end(); i++) - this->WriteServ("232 %s :- %s",this->nick,i->c_str()); + this->WriteNumeric(232, "%s :- %s",this->nick,i->c_str()); - this->WriteServ("309 %s :End of RULES command.",this->nick); + this->WriteNumeric(309, "%s :End of RULES command.",this->nick); } void User::HandleEvent(EventType et, int errornum) @@ -1711,7 +1846,7 @@ void User::HandleEvent(EventType et, int errornum) } catch (...) { - ServerInstance->Log(DEBUG,"Exception in User::HandleEvent intercepted"); + ServerInstance->Logs->Log("USERS", DEBUG,"Exception in User::HandleEvent intercepted"); } /* If the user has raised an error whilst being processed, quit them now we're safe to */