From ff3eef491aa9e107d09d9dd9560ef7715b37b3b3 Mon Sep 17 00:00:00 2001 From: danieldg Date: Wed, 21 Oct 2009 23:45:32 +0000 Subject: Move all local-only fields to LocalUser git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@11944 e03df62e-2008-0410-955e-edbf42e46eb7 --- include/users.h | 196 +++++++++++++++++++++----------------- src/channels.cpp | 28 +++--- src/command_parse.cpp | 10 +- src/commands/cmd_invite.cpp | 7 +- src/commands/cmd_nick.cpp | 3 +- src/commands/cmd_oper.cpp | 2 +- src/commands/cmd_pass.cpp | 8 +- src/commands/cmd_pong.cpp | 3 +- src/modules/extra/m_ldapauth.cpp | 7 +- src/modules/m_cgiirc.cpp | 4 +- src/modules/m_cloaking.cpp | 2 +- src/modules/m_override.cpp | 2 +- src/modules/m_sqlauth.cpp | 2 +- src/modules/m_testnet.cpp | 4 +- src/modules/m_uninvite.cpp | 31 +++--- src/usermanager.cpp | 8 +- src/users.cpp | 198 +++++++++++++++++++++------------------ 17 files changed, 275 insertions(+), 240 deletions(-) diff --git a/include/users.h b/include/users.h index 0be98f3bf..51600e3af 100644 --- a/include/users.h +++ b/include/users.h @@ -235,12 +235,6 @@ class User; class CoreExport User : public StreamSocket { private: - /** A list of channels the user has a pending invite to. - * Upon INVITE channels are added, and upon JOIN, the - * channels are removed from this list. - */ - InvitedList invites; - /** Cached nick!ident@dhost value using the displayed hostname */ std::string cached_fullhost; @@ -266,30 +260,13 @@ class CoreExport User : public StreamSocket * mode characters this user is making use of. */ void DecrementModes(); - - std::set *AllowedOperCommands; - std::set *AllowedPrivs; - - /** Allowed user modes from oper classes. */ - std::bitset<64> AllowedUserModes; - - /** Allowed channel modes from oper classes. */ - std::bitset<64> AllowedChanModes; - public: - /** Contains a pointer to the connect class a user is on from - this will be NULL for remote connections. - */ - reference MyClass; /** Hostname of connection. * This should be valid as per RFC1035. */ std::string host; - /** Time the connection was last pinged - */ - time_t lastping; - /** Time that the object was instantiated (used for TS calculation etc) */ time_t age; @@ -304,20 +281,12 @@ class CoreExport User : public StreamSocket */ time_t idle_lastmsg; - /** Used by PING checking code - */ - time_t nping; - /** Client address that the user is connected from. * Do not modify this value directly, use SetClientIP() to change it * Port is not valid for remote users. */ irc::sockets::sockaddrs client_sa; - /** Stored reverse lookup from res_forward. Should not be used after resolution. - */ - std::string stored_host; - /** The users nickname. * An invalid nickname indicates an unregistered connection prior to the NICK command. * Use InspIRCd::IsNick() to validate nicknames. @@ -360,7 +329,7 @@ class CoreExport User : public StreamSocket */ std::bitset<64> snomasks; - /** Channels this user is on, and the permissions they have there + /** Channels this user is on */ UserChanList chans; @@ -380,22 +349,11 @@ class CoreExport User : public StreamSocket /** The oper type they logged in as, if they are an oper. * This is used to check permissions in operclasses, so that - * we can say 'yay' or 'nay' to any commands they issue. - * The value of this is the value of a valid 'type name=' tag. + * we can say 'yea' or 'nay' to any commands they issue. + * The value of this was the value of a valid 'type name=' tag */ std::string oper; - /** Password specified by the user when they registered. - * This is stored even if the block doesnt need a password, so that - * modules may check it. - */ - std::string password; - - /** This value contains how far into the penalty threshold the user is. Once its over - * the penalty threshold then commands are held and processed on-timer. - */ - int Penalty; - /** Used by User to indicate the registration status of the connection * It is a bitfield of the REG_NICK, REG_USER and REG_ALL bits to indicate * the connection state. @@ -423,6 +381,10 @@ class CoreExport User : public StreamSocket */ unsigned int exempt:1; + /** has the user responded to their previous ping? + */ + unsigned int lastping:1; + /** Get client IP string from sockaddr, using static internal buffer * @return The IP string */ @@ -517,32 +479,13 @@ class CoreExport User : public StreamSocket */ void SetMode(unsigned char m, bool value); - /** Returns true if a user is invited to a channel. - * @param channel A channel name to look up - * @return True if the user is invited to the given channel - */ - virtual bool IsInvited(const irc::string &channel); - - /** Adds a channel to a users invite list (invites them to a channel) - * @param channel A channel name to add - * @param timeout When the invite should expire (0 == never) - */ - virtual void InviteTo(const irc::string &channel, time_t timeout); - - /** Removes a channel from a users invite list. - * This member function is called on successfully joining an invite only channel - * to which the user has previously been invited, to clear the invitation. - * @param channel The channel to remove the invite to - */ - virtual void RemoveInvite(const irc::string &channel); - /** Returns true or false for if a user can execute a privilaged oper command. * This is done by looking up their oper type from User::oper, then referencing * this to their oper classes and checking the commands they can execute. * @param command A command (should be all CAPS) * @return True if this user can execute the command */ - bool HasPermission(const std::string &command); + virtual bool HasPermission(const std::string &command); /** Returns true if a user has a given permission. * This is used to check whether or not users may perform certain actions which admins may not wish to give to @@ -552,7 +495,7 @@ class CoreExport User : public StreamSocket * @param noisy If set to true, the user is notified that they do not have the specified permission where applicable. If false, no notification is sent. * @return True if this user has the permission in question. */ - bool HasPrivPermission(const std::string &privstr, bool noisy = false); + virtual bool HasPrivPermission(const std::string &privstr, bool noisy = false); /** Returns true or false if a user can set a privileged user or channel mode. * This is done by looking up their oper type from User::oper, then referencing @@ -561,12 +504,7 @@ class CoreExport User : public StreamSocket * @param type ModeType (MODETYPE_CHANNEL or MODETYPE_USER). * @return True if the user can set or unset this mode. */ - bool HasModePermission(unsigned char mode, ModeType type); - - /** Returns the list of channels this user has been invited to but has not yet joined. - * @return A list of channels the user is invited to - */ - InvitedList* GetInviteList(); + virtual bool HasModePermission(unsigned char mode, ModeType type); /** Creates a wildcard host. * Takes a buffer to use and fills the given buffer with the host in the format *!*@hostname @@ -596,10 +534,6 @@ class CoreExport User : public StreamSocket */ void Oper(const std::string &opertype, const std::string &opername); - /** Call this method to find the matching for a user, and to check them against it. - */ - void CheckClass(); - /** Change this users hash key to a new string. * You should not call this function directly. It is used by the core * to update the users hash entry on a nickchange. @@ -786,10 +720,10 @@ class CoreExport User : public StreamSocket */ void PurgeEmptyChannels(); - /** Get the connect class which this user belongs to. - * @return A pointer to this user's connect class + /** Get the connect class which this user belongs to. NULL for remote users. + * @return A pointer to this user's connect class. */ - ConnectClass *GetClass(); + virtual ConnectClass* GetClass(); /** Show the message of the day to this user */ @@ -799,10 +733,6 @@ class CoreExport User : public StreamSocket */ void ShowRULES(); - /** Increases a user's command penalty by a set amount. - */ - void IncreasePenalty(int increase); - virtual void OnDataReady(); virtual void OnError(BufferedSocketError error); /** Default destructor @@ -821,6 +751,21 @@ class CoreExport User : public StreamSocket class CoreExport LocalUser : public User { + /** A list of channels the user has a pending invite to. + * Upon INVITE channels are added, and upon JOIN, the + * channels are removed from this list. + */ + InvitedList invites; + + std::set *AllowedOperCommands; + std::set *AllowedPrivs; + + /** Allowed user modes from oper classes. */ + std::bitset<64> AllowedUserModes; + + /** Allowed channel modes from oper classes. */ + std::bitset<64> AllowedChanModes; + public: LocalUser(); CullResult cull(); @@ -841,6 +786,22 @@ class CoreExport LocalUser : public User */ int cmds_out; + /** Password specified by the user when they registered (if any). + * This is stored even if the block doesnt need a password, so that + * modules may check it. + */ + std::string password; + + /** Contains a pointer to the connect class a user is on from + */ + reference MyClass; + + ConnectClass* GetClass(); + + /** Call this method to find the matching for a user, and to check them against it. + */ + void CheckClass(); + /** Server address and port that this user is connected to. */ irc::sockets::sockaddrs server_sa; @@ -850,6 +811,19 @@ class CoreExport LocalUser : public User */ int GetServerPort(); + /** Used by PING checking code + */ + time_t nping; + + /** This value contains how far into the penalty threshold the user is. Once its over + * the penalty threshold then commands are held and processed on-timer. + */ + int Penalty; + + /** Stored reverse lookup from res_forward. Should not be used after resolution. + */ + std::string stored_host; + /** Starts a DNS lookup of the user's IP. * This will cause two UserResolver classes to be instantiated. * When complete, these objects set User::dns_done to true. @@ -865,7 +839,7 @@ class CoreExport LocalUser : public User * @param explicit_name Set this string to tie the user to a specific class name. Otherwise, the class is fitted by checking tags from the configuration file. * @return A reference to this user's current connect class. */ - ConnectClass *SetClass(const std::string &explicit_name = ""); + void SetClass(const std::string &explicit_name = ""); void OnDataReady(); void SendText(const std::string& line); @@ -878,6 +852,60 @@ class CoreExport LocalUser : public User * @param data The data to add to the write buffer */ void AddWriteBuf(const std::string &data); + + /** Returns the list of channels this user has been invited to but has not yet joined. + * @return A list of channels the user is invited to + */ + InvitedList* GetInviteList(); + + /** Returns true if a user is invited to a channel. + * @param channel A channel name to look up + * @return True if the user is invited to the given channel + */ + bool IsInvited(const irc::string &channel); + + /** Adds a channel to a users invite list (invites them to a channel) + * @param channel A channel name to add + * @param timeout When the invite should expire (0 == never) + */ + void InviteTo(const irc::string &channel, time_t timeout); + + /** Removes a channel from a users invite list. + * This member function is called on successfully joining an invite only channel + * to which the user has previously been invited, to clear the invitation. + * @param channel The channel to remove the invite to + */ + void RemoveInvite(const irc::string &channel); + + /** Returns true or false for if a user can execute a privilaged oper command. + * This is done by looking up their oper type from User::oper, then referencing + * this to their oper classes and checking the commands they can execute. + * @param command A command (should be all CAPS) + * @return True if this user can execute the command + */ + bool HasPermission(const std::string &command); + + /** Returns true if a user has a given permission. + * This is used to check whether or not users may perform certain actions which admins may not wish to give to + * all operators, yet are not commands. An example might be oper override, mass messaging (/notice $*), etc. + * + * @param privstr The priv to chec, e.g. "users/override/topic". These are loaded free-form from the config file. + * @param noisy If set to true, the user is notified that they do not have the specified permission where applicable. If false, no notification is sent. + * @return True if this user has the permission in question. + */ + bool HasPrivPermission(const std::string &privstr, bool noisy = false); + + /** Returns true or false if a user can set a privileged user or channel mode. + * This is done by looking up their oper type from User::oper, then referencing + * this to their oper classes, and checking the modes they can set. + * @param mode The mode the check + * @param type ModeType (MODETYPE_CHANNEL or MODETYPE_USER). + * @return True if the user can set or unset this mode. + */ + bool HasModePermission(unsigned char mode, ModeType type); + + void OperInternal(); + void UnOperInternal(); }; class CoreExport RemoteUser : public User diff --git a/src/channels.cpp b/src/channels.cpp index d7f8f372e..d0d8e52c5 100644 --- a/src/channels.cpp +++ b/src/channels.cpp @@ -218,24 +218,20 @@ Channel* Channel::JoinUser(User *user, const char* cn, bool override, const char */ if (IS_LOCAL(user) && !override) { - // Checking MyClass exists because we *may* get here with NULL, not 100% sure. - if (user->MyClass && user->MyClass->maxchans) + if (user->HasPrivPermission("channels/high-join-limit")) { - if (user->HasPrivPermission("channels/high-join-limit")) + if (user->chans.size() >= ServerInstance->Config->OperMaxChans) { - if (user->chans.size() >= ServerInstance->Config->OperMaxChans) - { - user->WriteNumeric(ERR_TOOMANYCHANNELS, "%s %s :You are on too many channels",user->nick.c_str(), cn); - return NULL; - } + user->WriteNumeric(ERR_TOOMANYCHANNELS, "%s %s :You are on too many channels",user->nick.c_str(), cn); + return NULL; } - else + } + else + { + if (user->chans.size() >= user->GetClass()->maxchans) { - if (user->chans.size() >= user->MyClass->maxchans) - { - user->WriteNumeric(ERR_TOOMANYCHANNELS, "%s %s :You are on too many channels",user->nick.c_str(), cn); - return NULL; - } + user->WriteNumeric(ERR_TOOMANYCHANNELS, "%s %s :You are on too many channels",user->nick.c_str(), cn); + return NULL; } } } @@ -291,7 +287,7 @@ Channel* Channel::JoinUser(User *user, const char* cn, bool override, const char else if (MOD_RESULT == MOD_RES_PASSTHRU) { std::string ckey = Ptr->GetModeParameter('k'); - bool invited = user->IsInvited(Ptr->name.c_str()); + bool invited = IS_LOCAL(user)->IsInvited(Ptr->name.c_str()); bool can_bypass = ServerInstance->Config->InvBypassModes && invited; if (!ckey.empty()) @@ -338,7 +334,7 @@ Channel* Channel::JoinUser(User *user, const char* cn, bool override, const char */ if (invited) { - user->RemoveInvite(Ptr->name.c_str()); + IS_LOCAL(user)->RemoveInvite(Ptr->name.c_str()); } } } diff --git a/src/command_parse.cpp b/src/command_parse.cpp index 6dd4e663e..9fc8f85bb 100644 --- a/src/command_parse.cpp +++ b/src/command_parse.cpp @@ -249,11 +249,10 @@ bool CommandParser::ProcessCommand(User *user, std::string &cmd) /* Modify the user's penalty regardless of whether or not the command exists */ bool do_more = true; - if (!user->HasPrivPermission("users/flood/no-throttle")) + if (IS_LOCAL(user) && !user->HasPrivPermission("users/flood/no-throttle")) { // If it *doesn't* exist, give it a slightly heftier penalty than normal to deter flooding us crap - user->IncreasePenalty(cm != cmdlist.end() ? cm->second->Penalty : 2); - do_more = (user->GetClass()->GetPenaltyThreshold() && ((unsigned long)user->Penalty < user->GetClass()->GetPenaltyThreshold())); + IS_LOCAL(user)->Penalty += cm != cmdlist.end() ? cm->second->Penalty : 2; } @@ -328,8 +327,9 @@ bool CommandParser::ProcessCommand(User *user, std::string &cmd) return true; /* activity resets the ping pending timer */ - if (user->MyClass) - user->nping = ServerInstance->Time() + user->MyClass->GetPingTime(); + LocalUser* luser = IS_LOCAL(user); + if (luser) + luser->nping = ServerInstance->Time() + luser->MyClass->GetPingTime(); if (cm->second->flags_needed) { diff --git a/src/commands/cmd_invite.cpp b/src/commands/cmd_invite.cpp index 9da6096a4..84c522754 100644 --- a/src/commands/cmd_invite.cpp +++ b/src/commands/cmd_invite.cpp @@ -90,7 +90,8 @@ CmdResult CommandInvite::Handle (const std::vector& parameters, Use } } - u->InviteTo(c->name.c_str(), timeout); + if (IS_LOCAL(u)) + IS_LOCAL(u)->InviteTo(c->name.c_str(), timeout); u->WriteFrom(user,"INVITE %s :%s",u->nick.c_str(),c->name.c_str()); user->WriteNumeric(RPL_INVITING, "%s %s %s",user->nick.c_str(),u->nick.c_str(),c->name.c_str()); switch (ServerInstance->Config->AnnounceInvites) @@ -113,11 +114,11 @@ CmdResult CommandInvite::Handle (const std::vector& parameters, Use } FOREACH_MOD(I_OnUserInvite,OnUserInvite(user,u,c,timeout)); } - else + else if (IS_LOCAL(user)) { // pinched from ircu - invite with not enough parameters shows channels // youve been invited to but haven't joined yet. - InvitedList* il = user->GetInviteList(); + InvitedList* il = IS_LOCAL(user)->GetInviteList(); for (InvitedList::iterator i = il->begin(); i != il->end(); i++) { user->WriteNumeric(RPL_INVITELIST, "%s :%s",user->nick.c_str(),i->first.c_str()); diff --git a/src/commands/cmd_nick.cpp b/src/commands/cmd_nick.cpp index ee8c4625c..489551dd1 100644 --- a/src/commands/cmd_nick.cpp +++ b/src/commands/cmd_nick.cpp @@ -202,7 +202,8 @@ CmdResult CommandNick::Handle (const std::vector& parameters, User if (user->registered == REG_ALL) { - user->IncreasePenalty(10); + if (IS_LOCAL(user)) + IS_LOCAL(user)->Penalty += 10; FOREACH_MOD(I_OnUserPostNick,OnUserPostNick(user, oldnick)); } diff --git a/src/commands/cmd_oper.cpp b/src/commands/cmd_oper.cpp index dc15a5415..428e7b109 100644 --- a/src/commands/cmd_oper.cpp +++ b/src/commands/cmd_oper.cpp @@ -124,7 +124,7 @@ CmdResult CommandOper::HandleLocal(const std::vector& parameters, L // tell them they suck, and lag them up to help prevent brute-force attacks user->WriteNumeric(491, "%s :Invalid oper credentials",user->nick.c_str()); - user->IncreasePenalty(10); + user->Penalty += 10; snprintf(broadcast, MAXBUF, "WARNING! Failed oper attempt by %s!%s@%s using login '%s': The following fields do not match: %s", user->nick.c_str(), user->ident.c_str(), user->host.c_str(), parameters[0].c_str(), fields.c_str()); ServerInstance->SNO->WriteToSnoMask('o',std::string(broadcast)); diff --git a/src/commands/cmd_pass.cpp b/src/commands/cmd_pass.cpp index 21b5b2759..0bf1b46a4 100644 --- a/src/commands/cmd_pass.cpp +++ b/src/commands/cmd_pass.cpp @@ -18,23 +18,23 @@ * the same way, however, they can be fully unloaded, where these * may not. */ -class CommandPass : public Command +class CommandPass : public SplitCommand { public: /** Constructor for pass. */ - CommandPass ( Module* parent) : Command(parent,"PASS",1,1) { works_before_reg = true; Penalty = 0; syntax = ""; } + CommandPass (Module* parent) : SplitCommand(parent,"PASS",1,1) { works_before_reg = true; Penalty = 0; syntax = ""; } /** Handle command. * @param parameters The parameters to the comamnd * @param pcnt The number of parameters passed to teh command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ - CmdResult Handle(const std::vector& parameters, User *user); + CmdResult HandleLocal(const std::vector& parameters, LocalUser *user); }; -CmdResult CommandPass::Handle (const std::vector& parameters, User *user) +CmdResult CommandPass::HandleLocal(const std::vector& parameters, LocalUser *user) { // Check to make sure they haven't registered -- Fix by FCS if (user->registered == REG_ALL) diff --git a/src/commands/cmd_pong.cpp b/src/commands/cmd_pong.cpp index 225be147a..9bff00ed2 100644 --- a/src/commands/cmd_pong.cpp +++ b/src/commands/cmd_pong.cpp @@ -36,7 +36,8 @@ class CommandPong : public Command CmdResult CommandPong::Handle (const std::vector&, User *user) { // set the user as alive so they survive to next ping - user->lastping = 1; + if (IS_LOCAL(user)) + IS_LOCAL(user)->lastping = 1; return CMD_SUCCESS; } diff --git a/src/modules/extra/m_ldapauth.cpp b/src/modules/extra/m_ldapauth.cpp index 26e968367..af676de44 100644 --- a/src/modules/extra/m_ldapauth.cpp +++ b/src/modules/extra/m_ldapauth.cpp @@ -127,17 +127,16 @@ public: return MOD_RES_PASSTHRU; } - bool CheckCredentials(User* user) + bool CheckCredentials(LocalUser* user) { if (conn == NULL) if (!Connect()) return false; int res; - char* authpass = strdup(password.c_str()); // bind anonymously if no bind DN and authentication are given in the config struct berval cred; - cred.bv_val = authpass; + cred.bv_val = const_cast(password.c_str()); cred.bv_len = password.length(); if ((res = ldap_sasl_bind_s(conn, username.c_str(), LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL)) != LDAP_SUCCESS) @@ -155,13 +154,11 @@ public: { if (verbose) ServerInstance->SNO->WriteToSnoMask('c', "Forbidden connection from %s!%s@%s (LDAP bind failed: %s)", user->nick.c_str(), user->ident.c_str(), user->host.c_str(), ldap_err2string(res)); - free(authpass); ldap_unbind_ext(conn, NULL, NULL); conn = NULL; return false; } } - free(authpass); LDAPMessage *msg, *entry; std::string what = (attribute + "=" + (useusername ? user->ident : user->nick)); diff --git a/src/modules/m_cgiirc.cpp b/src/modules/m_cgiirc.cpp index 745dc13d2..5f8cfeca7 100644 --- a/src/modules/m_cgiirc.cpp +++ b/src/modules/m_cgiirc.cpp @@ -277,7 +277,7 @@ public: } } - bool CheckPass(User* user) + bool CheckPass(LocalUser* user) { if(IsValidHost(user->password)) { @@ -324,7 +324,7 @@ public: return false; } - bool CheckIdent(User* user) + bool CheckIdent(LocalUser* user) { const char* ident; int len = user->ident.length(); diff --git a/src/modules/m_cloaking.cpp b/src/modules/m_cloaking.cpp index 0ad790de9..c0ebbc99b 100644 --- a/src/modules/m_cloaking.cpp +++ b/src/modules/m_cloaking.cpp @@ -57,7 +57,7 @@ class CloakUser : public ModeHandler } /* don't allow this user to spam modechanges */ - dest->IncreasePenalty(5); + IS_LOCAL(dest)->Penalty += 5; if (adding) { diff --git a/src/modules/m_override.cpp b/src/modules/m_override.cpp index e37282525..8a3fcdd62 100644 --- a/src/modules/m_override.cpp +++ b/src/modules/m_override.cpp @@ -135,7 +135,7 @@ class ModuleOverride : public Module if ((chan->modes[CM_INVITEONLY]) && (CanOverride(user,"INVITE"))) { irc::string x(chan->name.c_str()); - if (!user->IsInvited(x)) + if (!IS_LOCAL(user)->IsInvited(x)) { if (RequireKey && keygiven != "override") { diff --git a/src/modules/m_sqlauth.cpp b/src/modules/m_sqlauth.cpp index a4c237e4e..3a4461480 100644 --- a/src/modules/m_sqlauth.cpp +++ b/src/modules/m_sqlauth.cpp @@ -85,7 +85,7 @@ public: return MOD_RES_PASSTHRU; } - bool CheckCredentials(User* user) + bool CheckCredentials(LocalUser* user) { std::string thisquery = freeformquery; std::string safepass = user->password; diff --git a/src/modules/m_testnet.cpp b/src/modules/m_testnet.cpp index 6a0cfa303..7f825a728 100644 --- a/src/modules/m_testnet.cpp +++ b/src/modules/m_testnet.cpp @@ -32,9 +32,9 @@ class CommandTest : public Command for(unsigned int i=0; i < count; i++) user->Write(line); } - else if (parameters[0] == "freeze") + else if (parameters[0] == "freeze" && IS_LOCAL(user)) { - user->Penalty += 100; + IS_LOCAL(user)->Penalty += 100; } else if (parameters[0] == "shutdown") { diff --git a/src/modules/m_uninvite.cpp b/src/modules/m_uninvite.cpp index 1215dd0df..fff51817e 100644 --- a/src/modules/m_uninvite.cpp +++ b/src/modules/m_uninvite.cpp @@ -56,28 +56,29 @@ class CommandUninvite : public Command irc::string xname(c->name.c_str()); - if (!u->IsInvited(xname)) + if (IS_LOCAL(u)) { - user->WriteNumeric(505, "%s %s %s :Is not invited to channel %s", user->nick.c_str(), u->nick.c_str(), c->name.c_str(), c->name.c_str()); - return CMD_FAILURE; - } - if (!c->HasUser(user)) - { - user->WriteNumeric(492, "%s %s :You're not on that channel!",user->nick.c_str(), c->name.c_str()); - return CMD_FAILURE; + // TODO send messages & such out to remote servers + LocalUser* lu = IS_LOCAL(u); + if (!lu->IsInvited(xname)) + { + user->WriteNumeric(505, "%s %s %s :Is not invited to channel %s", user->nick.c_str(), u->nick.c_str(), c->name.c_str(), c->name.c_str()); + return CMD_FAILURE; + } + user->WriteNumeric(494, "%s %s %s :Uninvited", user->nick.c_str(), c->name.c_str(), u->nick.c_str()); + lu->RemoveInvite(xname); + lu->WriteNumeric(493, "%s :You were uninvited from %s by %s", u->nick.c_str(), c->name.c_str(), user->nick.c_str()); + c->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :*** %s uninvited %s.", + c->name.c_str(), user->nick.c_str(), u->nick.c_str()); } - u->RemoveInvite(xname); - user->WriteNumeric(494, "%s %s %s :Uninvited", user->nick.c_str(), c->name.c_str(), u->nick.c_str()); - u->WriteNumeric(493, "%s :You were uninvited from %s by %s", u->nick.c_str(), c->name.c_str(), user->nick.c_str()); - c->WriteChannelWithServ(ServerInstance->Config->ServerName.c_str(), "NOTICE %s :*** %s uninvited %s.", c->name.c_str(), user->nick.c_str(), u->nick.c_str()); - return CMD_SUCCESS; } RouteDescriptor GetRouting(User* user, const std::vector& parameters) { - return ROUTE_BROADCAST; + User* u = ServerInstance->FindNick(parameters[0]); + return u ? ROUTE_UNICAST(u->server) : ROUTE_LOCALONLY; } }; @@ -98,7 +99,7 @@ class ModuleUninvite : public Module virtual Version GetVersion() { - return Version("Provides the UNINVITE command which lets users un-invite other users from channels (!)", VF_VENDOR | VF_COMMON); + return Version("Provides the UNINVITE command which lets users un-invite other users from channels", VF_VENDOR | VF_COMMON); } }; diff --git a/src/usermanager.cpp b/src/usermanager.cpp index 6889ddba3..2d824c6b2 100644 --- a/src/usermanager.cpp +++ b/src/usermanager.cpp @@ -81,13 +81,7 @@ void UserManager::AddUser(int socket, ClientListenSocket* via, irc::sockets::soc * First class check. We do this again in FullConnect after DNS is done, and NICK/USER is recieved. * See my note down there for why this is required. DO NOT REMOVE. :) -- w00t */ - ConnectClass* i = New->SetClass(); - - if (!i) - { - this->QuitUser(New, "Access denied by configuration"); - return; - } + New->SetClass(); /* * Check connect class settings and initialise settings into User. diff --git a/src/users.cpp b/src/users.cpp index dfb386871..bcf50a1ff 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -225,11 +225,9 @@ User::User(const std::string &uid) { server = ServerInstance->Config->ServerName; age = ServerInstance->Time(); - Penalty = 0; - lastping = signon = idle_lastmsg = nping = registered = 0; + signon = idle_lastmsg = registered = 0; quietquit = quitting = exempt = dns_done = false; fd = -1; - AllowedPrivs = AllowedOperCommands = NULL; uuid = uid; client_sa.sa.sa_family = AF_UNSPEC; @@ -244,8 +242,11 @@ User::User(const std::string &uid) LocalUser::LocalUser() : User(ServerInstance->GetUID()) { + AllowedPrivs = AllowedOperCommands = NULL; bytes_in = bytes_out = cmds_in = cmds_out = 0; server_sa.sa.sa_family = AF_UNSPEC; + Penalty = 0; + lastping = nping = 0; } User::~User() @@ -350,7 +351,7 @@ const std::string User::GetFullRealHost() return this->cached_fullrealhost; } -bool User::IsInvited(const irc::string &channel) +bool LocalUser::IsInvited(const irc::string &channel) { time_t now = ServerInstance->Time(); InvitedList::iterator safei; @@ -372,7 +373,7 @@ bool User::IsInvited(const irc::string &channel) return false; } -InvitedList* User::GetInviteList() +InvitedList* LocalUser::GetInviteList() { time_t now = ServerInstance->Time(); /* Weed out expired invites here. */ @@ -390,7 +391,7 @@ InvitedList* User::GetInviteList() return &invites; } -void User::InviteTo(const irc::string &channel, time_t invtimeout) +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. */ @@ -409,7 +410,7 @@ void User::InviteTo(const irc::string &channel, time_t invtimeout) invites.push_back(std::make_pair(channel, invtimeout)); } -void User::RemoveInvite(const irc::string &channel) +void LocalUser::RemoveInvite(const irc::string &channel) { for (InvitedList::iterator i = invites.begin(); i != invites.end(); i++) { @@ -421,11 +422,13 @@ void User::RemoveInvite(const irc::string &channel) } } -bool User::HasModePermission(unsigned char mode, ModeType type) +bool User::HasModePermission(unsigned char, ModeType) { - if (!IS_LOCAL(this)) - return true; + return true; +} +bool LocalUser::HasModePermission(unsigned char mode, ModeType type) +{ if (!IS_OPER(this)) return false; @@ -434,19 +437,20 @@ bool User::HasModePermission(unsigned char mode, ModeType type) return ((type == MODETYPE_USER ? AllowedUserModes : AllowedChanModes))[(mode - 'A')]; } - -bool User::HasPermission(const std::string &command) +/* + * 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&) { - /* - * 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. - */ - if (!IS_LOCAL(this)) - return true; + return true; +} +bool LocalUser::HasPermission(const std::string &command) +{ // are they even an oper at all? if (!IS_OPER(this)) { @@ -464,15 +468,13 @@ bool User::HasPermission(const std::string &command) return false; } - bool User::HasPrivPermission(const std::string &privstr, bool noisy) { - if (!IS_LOCAL(this)) - { - ServerInstance->Logs->Log("PRIVS", DEBUG, "Remote (yes)"); - return true; - } + return true; +} +bool LocalUser::HasPrivPermission(const std::string &privstr, bool noisy) +{ if (!IS_OPER(this)) { if (noisy) @@ -510,14 +512,14 @@ void LocalUser::OnDataReady() if (quitting) return; - if (MyClass && recvq.length() > MyClass->GetRecvqMax() && !HasPrivPermission("users/flood/increased-buffers")) + if (recvq.length() > MyClass->GetRecvqMax() && !HasPrivPermission("users/flood/increased-buffers")) { ServerInstance->Users->QuitUser(this, "RecvQ exceeded"); ServerInstance->SNO->WriteToSnoMask('a', "User %s RecvQ of %lu exceeds connect class maximum of %lu", nick.c_str(), (unsigned long)recvq.length(), MyClass->GetRecvqMax()); } unsigned long sendqmax = ULONG_MAX; - if (MyClass && !HasPrivPermission("users/flood/increased-buffers")) + if (!HasPrivPermission("users/flood/increased-buffers")) sendqmax = MyClass->GetSendqSoftMax(); int penaltymax = MyClass->GetPenaltyThreshold(); if (penaltymax == 0 || HasPrivPermission("users/flood/no-fakelag")) @@ -566,7 +568,7 @@ eol_found: void LocalUser::AddWriteBuf(const std::string &data) { - if (!quitting && MyClass && getSendQSize() + data.length() > MyClass->GetSendqHardMax() && !HasPrivPermission("users/flood/increased-buffers")) + if (!quitting && getSendQSize() + data.length() > MyClass->GetSendqHardMax() && !HasPrivPermission("users/flood/increased-buffers")) { /* * Quit the user FIRST, because otherwise we could recurse @@ -602,18 +604,6 @@ CullResult User::cull() if (IS_LOCAL(this) && fd != INT_MAX) Close(); - if (this->AllowedOperCommands) - { - delete AllowedOperCommands; - AllowedOperCommands = NULL; - } - - if (this->AllowedPrivs) - { - delete AllowedPrivs; - AllowedPrivs = NULL; - } - this->InvalidateCache(); this->DecrementModes(); @@ -630,6 +620,18 @@ CullResult LocalUser::cull() else ServerInstance->Logs->Log("USERS", DEBUG, "Failed to remove user from vector"); + if (this->AllowedOperCommands) + { + delete AllowedOperCommands; + AllowedOperCommands = NULL; + } + + if (this->AllowedPrivs) + { + delete AllowedPrivs; + AllowedPrivs = NULL; + } + if (client_sa.sa.sa_family != AF_UNSPEC) ServerInstance->Users->RemoveCloneCounts(this); return User::cull(); @@ -651,6 +653,14 @@ void User::Oper(const std::string &opertype, const std::string &opername) this->oper.assign(opertype, 0, 512); ServerInstance->Users->all_opers.push_back(this); + if (IS_LOCAL(this)) + IS_LOCAL(this)->OperInternal(); + + FOREACH_MOD(I_OnPostOper,OnPostOper(this, opertype, opername)); +} + +void LocalUser::OperInternal() +{ /* * This might look like it's in the wrong place. * It is *not*! @@ -721,60 +731,64 @@ void User::Oper(const std::string &opertype, const std::string &opername) } } } - - FOREACH_MOD(I_OnPostOper,OnPostOper(this, opertype, opername)); } void User::UnOper() { - if (IS_OPER(this)) - { - /* - * unset their oper type (what IS_OPER checks). - * note, order is important - this must come before modes as -o attempts - * to call UnOper. -- w00t - */ - this->oper.clear(); + if (!IS_OPER(this)) + return; + /* + * unset their oper type (what IS_OPER checks). + * note, order is important - this must come before modes as -o attempts + * to call UnOper. -- w00t + */ + this->oper.clear(); - /* Remove all oper only modes from the user when the deoper - Bug #466*/ - std::string moderemove("-"); - for (unsigned char letter = 'A'; letter <= 'z'; letter++) - { - ModeHandler* mh = ServerInstance->Modes->FindMode(letter, MODETYPE_USER); - if (mh && mh->NeedsOper()) - moderemove += letter; - } + /* Remove all oper only modes from the user when the deoper - Bug #466*/ + std::string moderemove("-"); + for (unsigned char letter = 'A'; letter <= 'z'; letter++) + { + ModeHandler* mh = ServerInstance->Modes->FindMode(letter, MODETYPE_USER); + if (mh && mh->NeedsOper()) + moderemove += letter; + } - std::vector parameters; - parameters.push_back(this->nick); - parameters.push_back(moderemove); - ServerInstance->Parser->CallHandler("MODE", parameters, this); + std::vector parameters; + parameters.push_back(this->nick); + parameters.push_back(moderemove); - /* remove the user from the oper list. Will remove multiple entries as a safeguard against bug #404 */ - ServerInstance->Users->all_opers.remove(this); + ServerInstance->Parser->CallHandler("MODE", parameters, this); - if (AllowedOperCommands) - { - delete AllowedOperCommands; - AllowedOperCommands = NULL; - } + /* remove the user from the oper list. Will remove multiple entries as a safeguard against bug #404 */ + ServerInstance->Users->all_opers.remove(this); - if (AllowedPrivs) - { - delete AllowedPrivs; - AllowedPrivs = NULL; - } + if (IS_LOCAL(this)) + IS_LOCAL(this)->UnOperInternal(); + this->modes[UM_OPERATOR] = 0; +} - AllowedUserModes.reset(); - AllowedChanModes.reset(); - this->modes[UM_OPERATOR] = 0; +void LocalUser::UnOperInternal() +{ + if (AllowedOperCommands) + { + delete AllowedOperCommands; + AllowedOperCommands = NULL; + } + + if (AllowedPrivs) + { + delete AllowedPrivs; + AllowedPrivs = NULL; } + AllowedUserModes.reset(); + AllowedChanModes.reset(); } + /* adds or updates an entry in the whowas list */ void User::AddToWhoWas() { @@ -790,11 +804,15 @@ void User::AddToWhoWas() /* * Check class restrictions */ -void User::CheckClass() +void LocalUser::CheckClass() { ConnectClass* a = this->MyClass; - if ((!a) || (a->type == CC_DENY)) + if (!a) + { + ServerInstance->Users->QuitUser(this, "Access denied by configuration"); + } + else if (a->type == CC_DENY) { ServerInstance->Users->QuitUser(this, "Unauthorised connection"); return; @@ -852,7 +870,7 @@ void LocalUser::FullConnect() /* Check the password, if one is required by the user's connect class. * This CANNOT be in CheckClass(), because that is called prior to PASS as well! */ - if (MyClass && !MyClass->pass.empty()) + if (!MyClass->pass.empty()) { if (ServerInstance->PassCompare(this, MyClass->pass.c_str(), password.c_str(), MyClass->hash.c_str())) { @@ -1641,7 +1659,7 @@ void User::SplitChanList(User* dest, const std::string &cl) * then their ip will be taken as 'priority' anyway, so for example, * will match joe!bloggs@localhost */ -ConnectClass* LocalUser::SetClass(const std::string &explicit_name) +void LocalUser::SetClass(const std::string &explicit_name) { ConnectClass *found = NULL; @@ -1719,8 +1737,6 @@ ConnectClass* LocalUser::SetClass(const std::string &explicit_name) { MyClass = found; } - - return this->MyClass; } /* looks up a users password for their connection class (/ tags) @@ -1728,9 +1744,14 @@ ConnectClass* LocalUser::SetClass(const std::string &explicit_name) * then their ip will be taken as 'priority' anyway, so for example, * will match joe!bloggs@localhost */ +ConnectClass* LocalUser::GetClass() +{ + return MyClass; +} + ConnectClass* User::GetClass() { - return this->MyClass; + return NULL; } void User::PurgeEmptyChannels() @@ -1776,11 +1797,6 @@ void User::ShowRULES() this->WriteNumeric(RPL_RULESEND, "%s :End of RULES command.",this->nick.c_str()); } -void User::IncreasePenalty(int increase) -{ - this->Penalty += increase; -} - void FakeUser::SetFakeServer(std::string name) { this->nick = name; -- cgit v1.2.3