void Snomask::SendMessage(const std::string &message) { if (message != LastMessage) { this->Flush(); LastMessage = message; std::string desc = this->Description; int MOD_RESULT = 0; char mysnomask = MySnomask; ServerInstance->Logs->Log("snomask", DEFAULT, "%s: %s", desc.c_str(), message.c_str()); FOREACH_RESULT(I_OnSendSnotice, OnSendSnotice(mysnomask, desc, message)); LastBlocked = (MOD_RESULT == 1); // 1 blocks the message if (!LastBlocked) { /* Only opers can receive snotices, so we iterate the oper list */ std::list<User*>::iterator i = ServerInstance->Users->all_opers.begin(); while (i != ServerInstance->Users->all_opers.end()) { User* a = *i; if (IS_LOCAL(a) && a->IsModeSet('s') && a->IsNoticeMaskSet(mysnomask) && !a->quitting) { a->WriteServ("NOTICE %s :*** %s: %s", a->nick.c_str(), desc.c_str(), message.c_str()); } i++; } } } Count++; }
static bool HasPriv(const AccessGroup &ag, const ChanAccess *access, const Anope::string &name) { EventReturn MOD_RESULT; FOREACH_RESULT(OnCheckPriv, MOD_RESULT, (access, name)); if (MOD_RESULT == EVENT_ALLOW || access->HasPriv(name)) { typedef std::multimap<const ChanAccess *, const ChanAccess *> path; std::pair<path::const_iterator, path::const_iterator> it = ag.path.second.equal_range(access); if (it.first != it.second) /* check all of the paths for this entry */ for (; it.first != it.second; ++it.first) { const ChanAccess *a = it.first->second; /* if only one path fully matches then we are ok */ if (HasPriv(ag, a, name)) return true; } else /* entry is the end of a chain, all entries match, ok */ return true; } /* entry does not match or none of the chains fully match */ return false; }
bool AccessGroup::HasPriv(const Anope::string &name) const { if (this->super_admin) return true; else if (!ci || ci->GetLevel(name) == ACCESS_INVALID) return false; /* Privileges prefixed with auto are understood to be given * automatically. Sometimes founders want to not automatically * obtain privileges, so we will let them */ bool auto_mode = !name.find("AUTO"); /* Only grant founder privilege if this isn't an auto mode or if they don't match any entries in this group */ if ((!auto_mode || this->empty()) && this->founder) return true; EventReturn MOD_RESULT; FOREACH_RESULT(OnGroupCheckPriv, MOD_RESULT, (this, name)); if (MOD_RESULT != EVENT_CONTINUE) return MOD_RESULT == EVENT_ALLOW; for (unsigned i = this->size(); i > 0; --i) { ChanAccess *access = this->at(i - 1); if (::HasPriv(*this, access, name)) return true; } return false; }
/* @return 1 to block the command, 0 to allow */ virtual int OnPreCommand(std::string &command, std::vector<std::string> ¶meters, User *user, bool validated, const std::string &original_line) { if (!validated || !ghosting) { return 0; } if (command == "NICK") { if (user->registered != REG_ALL) { /* Nick in use, ghosting is on if we reach here so process */ if (ServerInstance->FindNickOnly(parameters[0])) { /* We just let the user keep his UUID nick and fake further * down that the initial NICK was ok. For now just store * their wanted nick. */ std::string* authnick = new std::string(parameters[0]); user->Extend("wantsnick", authnick); /* since we cheat here, make them look as if they have passed * REG_NICK checks. HACK warning! Well its all hack this bit :) */ user->registered = (user->registered | REG_NICK); /* if NICK is sent after USER thus making the user fully NICKUSER * regged, we better trigger OnUserRegister since cmd_nick would * normally do this. Since we handle NICK we got to check and do it. */ if (user->registered == REG_NICKUSER) { int MOD_RESULT = 0; FOREACH_RESULT(I_OnUserRegister,OnUserRegister(user)); if (MOD_RESULT > 0) { return 1; } } /* Dont let inspircd process the command, we just did */ return 1; } } } return 0; }
void DoCheckAuthentication(XMLRPCServiceInterface *iface, XMLRPCClientSocket *source, XMLRPCRequest *request) { Anope::string username = request->data.size() > 0 ? request->data[0] : ""; Anope::string password = request->data.size() > 1 ? request->data[1] : ""; if (username.empty() || password.empty()) request->reply("error", "Invalid parameters"); else { NickAlias *na = findnick(username); if (!na) request->reply("error", "Invalid account"); else { EventReturn MOD_RESULT; FOREACH_RESULT(I_OnCheckAuthentication, OnCheckAuthentication(NULL, NULL, std::vector<Anope::string>(), na->nc->display, password)); if (MOD_RESULT == EVENT_ALLOW) { request->reply("result", "Success"); request->reply("account", na->nc->display); } else request->reply("error", "Invalid password"); } } }
std::string ModeChannelVoice::AddVoice(userrec *user,const char* dest,chanrec *chan,int status) { userrec *d = ServerInstance->Modes->SanityChecks(user,dest,chan,status); if (d) { if (IS_LOCAL(user)) { int MOD_RESULT = 0; FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user,d,chan,AC_VOICE)); if (MOD_RESULT == ACR_DENY) return ""; if (MOD_RESULT == ACR_DEFAULT) { if ((status < STATUS_HOP) && (!ServerInstance->ULine(user->server))) { user->WriteServ("482 %s %s :You're not a channel (half)operator",user->nick, chan->name); return ""; } } } return ServerInstance->Modes->Grant(d,chan,UCMODE_VOICE); } return ""; }
std::string ModeChannelOp::AddOp(User *user,const char* dest,Channel *chan,int status) { User *d = ServerInstance->Modes->SanityChecks(user,dest,chan,status); if (d) { if (IS_LOCAL(user)) { int MOD_RESULT = 0; FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user,d,chan,AC_OP)); if (MOD_RESULT == ACR_DENY) return ""; if (MOD_RESULT == ACR_DEFAULT) { if ((status < STATUS_OP) && (!ServerInstance->ULine(user->server))) { user->WriteServ("482 %s %s :You're not a channel operator",user->nick.c_str(), chan->name.c_str()); return ""; } } } return ServerInstance->Modes->Grant(d,chan,UCMODE_OP); } return ""; }
std::string ModeChannelOp::DelOp(userrec *user,const char *dest,chanrec *chan,int status) { userrec *d = ServerInstance->Modes->SanityChecks(user,dest,chan,status); if (d) { if (IS_LOCAL(user)) { int MOD_RESULT = 0; ServerInstance->Log(DEBUG,"Call OnAccessCheck for AC_DEOP"); FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user,d,chan,AC_DEOP)); ServerInstance->Log(DEBUG,"Returns %d",MOD_RESULT); if (MOD_RESULT == ACR_DENY) return ""; if (MOD_RESULT == ACR_DEFAULT) { if ((status < STATUS_OP) && (!ServerInstance->ULine(user->server)) && (IS_LOCAL(user))) { user->WriteServ("482 %s %s :You are not a channel operator",user->nick, chan->name); return ""; } } } return ServerInstance->Modes->Revoke(d,chan,UCMODE_OP); } return ""; }
void cmd_kill::Handle (const char** parameters, int pcnt, userrec *user) { userrec *u = ServerInstance->FindNick(parameters[0]); char killreason[MAXBUF]; int MOD_RESULT = 0; ServerInstance->Log(DEBUG,"kill: %s %s", parameters[0], parameters[1]); if (u) { ServerInstance->Log(DEBUG, "into kill mechanism"); FOREACH_RESULT(I_OnKill, OnKill(user, u, parameters[1])); if (MOD_RESULT) { ServerInstance->Log(DEBUG, "A module prevented the kill with result %d", MOD_RESULT); return; } if (!IS_LOCAL(u)) { // remote kill ServerInstance->WriteOpers("*** Remote kill by %s: %s!%s@%s (%s)", user->nick, u->nick, u->ident, u->host, parameters[1]); snprintf(killreason, MAXQUIT,"[%s] Killed (%s (%s))", ServerInstance->Config->ServerName, user->nick, parameters[1]); u->WriteCommonExcept("QUIT :%s", killreason); FOREACH_MOD(I_OnRemoteKill, OnRemoteKill(user, u, killreason)); user_hash::iterator iter = ServerInstance->clientlist.find(u->nick); if (iter != ServerInstance->clientlist.end()) { ServerInstance->Log(DEBUG,"deleting user hash value %d", iter->second); ServerInstance->clientlist.erase(iter); } if (u->registered == REG_ALL) { u->PurgeEmptyChannels(); } DELETE(u); } else { // local kill ServerInstance->Log(DEFAULT,"LOCAL KILL: %s :%s!%s!%s (%s)", u->nick, ServerInstance->Config->ServerName, user->dhost, user->nick, parameters[1]); user->WriteTo(u, "KILL %s :%s!%s!%s (%s)", u->nick, ServerInstance->Config->ServerName, user->dhost, user->nick, parameters[1]); ServerInstance->WriteOpers("*** Local Kill by %s: %s!%s@%s (%s)", user->nick, u->nick, u->ident, u->host, parameters[1]); snprintf(killreason,MAXQUIT,"Killed (%s (%s))", user->nick, parameters[1]); userrec::QuitUser(ServerInstance, u, killreason); } } else { user->WriteServ( "401 %s %s :No such nick/channel", user->nick, parameters[0]); } }
CmdResult cmd_user::Handle (const char** parameters, int pcnt, userrec *user) { /* A user may only send the USER command once */ if (!(user->registered & REG_USER)) { if (!ServerInstance->IsIdent(parameters[0])) { /* * RFC says we must use this numeric, so we do. Let's make it a little more nub friendly though. :) * -- Craig, and then w00t. */ user->WriteServ("461 %s USER :Your username is not valid",user->nick); return CMD_FAILURE; } else { /* * The ident field is IDENTMAX+2 in size to account for +1 for the optional * ~ character, and +1 for null termination, therefore we can safely use up to * IDENTMAX here. */ strlcpy(user->ident, parameters[0], IDENTMAX); strlcpy(user->fullname, *parameters[3] ? parameters[3] : "No info", MAXGECOS); user->registered = (user->registered | REG_USER); } } else { user->WriteServ("462 %s :You may not reregister",user->nick); return CMD_FAILURE; } /* parameters 2 and 3 are local and remote hosts, and are ignored */ if (user->registered == REG_NICKUSER) { int MOD_RESULT = 0; /* user is registered now, bit 0 = USER command, bit 1 = sent a NICK command */ if (ServerInstance->next_call > ServerInstance->Time() + ServerInstance->Config->dns_timeout) ServerInstance->next_call = ServerInstance->Time() + ServerInstance->Config->dns_timeout; FOREACH_RESULT(I_OnUserRegister,OnUserRegister(user)); if (MOD_RESULT > 0) return CMD_FAILURE; } return CMD_SUCCESS; }
void Command::Run(CommandSource &source, const Anope::string &cmdname, const CommandInfo &info, std::vector<Anope::string> ¶ms) { if (this->RequireUser() && !source.GetUser()) return; // Command requires registered users only if (!this->AllowUnregistered() && !source.nc) { source.Reply(NICK_IDENTIFY_REQUIRED); if (source.GetUser()) Log(LOG_NORMAL, "access_denied_unreg", source.service) << "Access denied for unregistered user " << source.GetUser()->GetMask() << " with command " << cmdname; return; } source.command = cmdname; source.permission = info.permission; EventReturn MOD_RESULT; FOREACH_RESULT(OnPreCommand, MOD_RESULT, (source, this, params)); if (MOD_RESULT == EVENT_STOP) return; if (params.size() < this->min_params) { this->OnSyntaxError(source, !params.empty() ? params[params.size() - 1] : ""); return; } // If the command requires a permission, and they aren't registered or don't have the required perm, DENIED if (!info.permission.empty() && !source.HasCommand(info.permission)) { source.Reply(ACCESS_DENIED); if (source.GetUser()) Log(LOG_NORMAL, "access_denied", source.service) << "Access denied for user " << source.GetUser()->GetMask() << " with command " << cmdname; return; } this->Execute(source, params); FOREACH_MOD(OnPostCommand, (source, this, params)); }
void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) { User *u = source.u; const Anope::string &nick = params.size() == 2 ? params[0] : u->nick; Anope::string pass = params[params.size() - 1]; NickAlias *na = findnick(nick); if (na && na->nc->HasFlag(NI_SUSPENDED)) source.Reply(NICK_X_SUSPENDED, na->nick.c_str()); else if (u->Account() && na && u->Account() == na->nc) source.Reply(_("You are already identified.")); else { EventReturn MOD_RESULT; FOREACH_RESULT(I_OnCheckAuthentication, OnCheckAuthentication(this, &source, params, na ? na->nc->display : nick, pass)); if (MOD_RESULT == EVENT_STOP) return; if (!na) source.Reply(NICK_X_NOT_REGISTERED, nick.c_str()); else if (MOD_RESULT != EVENT_ALLOW) { Log(LOG_COMMAND, u, this) << "and failed to identify"; source.Reply(PASSWORD_INCORRECT); bad_password(u); } else { if (u->IsIdentified()) Log(LOG_COMMAND, u, this) << "to log out of account " << u->Account()->display; Log(LOG_COMMAND, u, this) << "and identified for account " << na->nc->display; source.Reply(_("Password accepted - you are now recognized.")); u->Identify(na); } } return; }
void cmd_nick::Handle (const char** parameters, int pcnt, userrec *user) { char oldnick[NICKMAX]; if (pcnt < 1) { ServerInstance->Log(DEBUG,"not enough params for handle_nick"); return; } if (!parameters[0]) { ServerInstance->Log(DEBUG,"invalid parameter passed to handle_nick"); return; } if (!parameters[0][0]) { ServerInstance->Log(DEBUG,"zero length new nick passed to handle_nick"); return; } if (!user) { ServerInstance->Log(DEBUG,"invalid user passed to handle_nick"); return; } if (!user->nick) { ServerInstance->Log(DEBUG,"invalid old nick passed to handle_nick"); return; } if (irc::string(user->nick) == irc::string(parameters[0])) { /* If its exactly the same, even case, dont do anything. */ if (!strcmp(user->nick,parameters[0])) return; /* Its a change of case. People insisted that they should be * able to do silly things like this even though the RFC says * the nick AAA is the same as the nick aaa. */ ServerInstance->Log(DEBUG,"old nick is new nick, not updating hash (case change only)"); strlcpy(oldnick, user->nick, NICKMAX - 1); int MOD_RESULT = 0; FOREACH_RESULT(I_OnUserPreNick,OnUserPreNick(user,parameters[0])); if (MOD_RESULT) return; if (user->registered == REG_ALL) user->WriteCommon("NICK %s",parameters[0]); strlcpy(user->nick, parameters[0], NICKMAX - 1); FOREACH_MOD(I_OnUserPostNick,OnUserPostNick(user,oldnick)); return; } else { if ((*parameters[0] == ':') && (*(parameters[0]+1) != 0)) { parameters[0]++; } char* mq = ServerInstance->XLines->matches_qline(parameters[0]); if (mq) { ServerInstance->WriteOpers("*** Q-Lined nickname %s from %s!%s@%s: %s",parameters[0],user->nick,user->ident,user->host,mq); user->WriteServ("432 %s %s :Invalid nickname: %s",user->nick,parameters[0],mq); return; } if ((ServerInstance->FindNick(parameters[0])) && (ServerInstance->FindNick(parameters[0]) != user)) { user->WriteServ("433 %s %s :Nickname is already in use.",user->nick,parameters[0]); return; } } if ((!ServerInstance->IsNick(parameters[0])) && (IS_LOCAL(user))) { user->WriteServ("432 %s %s :Erroneous Nickname",user->nick,parameters[0]); return; } if (user->registered == REG_ALL) { int MOD_RESULT = 0; FOREACH_RESULT(I_OnUserPreNick,OnUserPreNick(user,parameters[0])); if (MOD_RESULT) { // if a module returns true, the nick change is silently forbidden. return; } user->WriteCommon("NICK %s",parameters[0]); } strlcpy(oldnick, user->nick, NICKMAX - 1); /* change the nick of the user in the users_hash */ user = user->UpdateNickHash(parameters[0]); /* actually change the nick within the record */ if (!user) return; if (!user->nick) return; strlcpy(user->nick, parameters[0], NICKMAX - 1); ServerInstance->Log(DEBUG,"new nick set: %s",user->nick); if (user->registered < REG_NICKUSER) { user->registered = (user->registered | REG_NICK); // dont attempt to look up the dns until they pick a nick... because otherwise their pointer WILL change // and unless we're lucky we'll get a duff one later on. //user->dns_done = (!lookup_dns(user->nick)); //if (user->dns_done) // ServerInstance->Log(DEBUG,"Aborting dns lookup of %s because dns server experienced a failure.",user->nick); if (ServerInstance->Config->NoUserDns) { user->dns_done = true; } else { user->StartDNSLookup(); if (user->dns_done) ServerInstance->Log(DEBUG,"Aborting dns lookup of %s because dns server experienced a failure.",user->nick); } } if (user->registered == REG_NICKUSER) { /* user is registered now, bit 0 = USER command, bit 1 = sent a NICK command */ FOREACH_MOD(I_OnUserRegister,OnUserRegister(user)); //ConnectUser(user,NULL); } if (user->registered == REG_ALL) { FOREACH_MOD(I_OnUserPostNick,OnUserPostNick(user,oldnick)); } }
bool ChannelMode::CanSet(User *u) const { EventReturn MOD_RESULT; FOREACH_RESULT(OnCanSet, MOD_RESULT, (u, this)); return MOD_RESULT != EVENT_STOP; }
CmdResult cmd_privmsg::Handle (const char** parameters, int pcnt, userrec *user) { userrec *dest; chanrec *chan; CUList except_list; user->idle_lastmsg = ServerInstance->Time(); if (ServerInstance->Parser->LoopCall(user, this, parameters, pcnt, 0)) return CMD_SUCCESS; if ((parameters[0][0] == '$') && (IS_OPER(user) || ServerInstance->ULine(user->server))) { int MOD_RESULT = 0; std::string temp = parameters[1]; FOREACH_RESULT(I_OnUserPreMessage,OnUserPreMessage(user,(void*)parameters[0],TYPE_SERVER,temp,0,except_list)); if (MOD_RESULT) return CMD_FAILURE; parameters[1] = temp.c_str(); // notice to server mask const char* servermask = parameters[0] + 1; if (match(ServerInstance->Config->ServerName,servermask)) { user->SendAll("PRIVMSG", "%s", parameters[1]); } FOREACH_MOD(I_OnUserMessage,OnUserMessage(user,(void*)parameters[0],TYPE_SERVER,parameters[1],0,except_list)); return CMD_SUCCESS; } char status = 0; if ((*parameters[0] == '@') || (*parameters[0] == '%') || (*parameters[0] == '+')) { status = *parameters[0]; parameters[0]++; } if (parameters[0][0] == '#') { chan = ServerInstance->FindChan(parameters[0]); except_list[user] = user->nick; if (chan) { if (IS_LOCAL(user)) { if ((chan->IsModeSet('n')) && (!chan->HasUser(user))) { user->WriteServ("404 %s %s :Cannot send to channel (no external messages)", user->nick, chan->name); return CMD_FAILURE; } if ((chan->IsModeSet('m')) && (chan->GetStatus(user) < STATUS_VOICE)) { user->WriteServ("404 %s %s :Cannot send to channel (+m)", user->nick, chan->name); return CMD_FAILURE; } } int MOD_RESULT = 0; std::string temp = parameters[1]; FOREACH_RESULT(I_OnUserPreMessage,OnUserPreMessage(user,chan,TYPE_CHANNEL,temp,status,except_list)); if (MOD_RESULT) { return CMD_FAILURE; } parameters[1] = temp.c_str(); /* Check again, a module may have zapped the input string */ if (temp.empty()) { user->WriteServ("412 %s :No text to send", user->nick); return CMD_FAILURE; } if (status) { if (ServerInstance->Config->UndernetMsgPrefix) { chan->WriteAllExcept(user, false, status, except_list, "PRIVMSG %c%s :%c %s", status, chan->name, status, parameters[1]); } else { chan->WriteAllExcept(user, false, status, except_list, "PRIVMSG %c%s :%s", status, chan->name, parameters[1]); } } else { chan->WriteAllExcept(user, false, status, except_list, "PRIVMSG %s :%s", chan->name, parameters[1]); } FOREACH_MOD(I_OnUserMessage,OnUserMessage(user,chan,TYPE_CHANNEL,parameters[1],status,except_list)); } else { /* no such nick/channel */ user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]); return CMD_FAILURE; } return CMD_SUCCESS; } dest = ServerInstance->FindNick(parameters[0]); if (dest) { if (!*parameters[1]) { user->WriteServ("412 %s :No text to send", user->nick); return CMD_FAILURE; } if (IS_AWAY(dest)) { /* auto respond with aweh msg */ user->WriteServ("301 %s %s :%s",user->nick,dest->nick,dest->awaymsg); } int MOD_RESULT = 0; std::string temp = parameters[1]; FOREACH_RESULT(I_OnUserPreMessage,OnUserPreMessage(user,dest,TYPE_USER,temp,0,except_list)); if (MOD_RESULT) { return CMD_FAILURE; } parameters[1] = (char*)temp.c_str(); if (IS_LOCAL(dest)) { // direct write, same server user->WriteTo(dest, "PRIVMSG %s :%s", dest->nick, parameters[1]); } FOREACH_MOD(I_OnUserMessage,OnUserMessage(user,dest,TYPE_USER,parameters[1],0,except_list)); } else { /* no such nick/channel */ user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]); return CMD_FAILURE; } return CMD_SUCCESS; }
CmdResult CommandNotice::Handle (const std::vector<std::string>& parameters, User *user) { User *dest; Channel *chan; CUList exempt_list; user->idle_lastmsg = ServerInstance->Time(); if (ServerInstance->Parser->LoopCall(user, this, parameters, 0)) return CMD_SUCCESS; if (parameters[0][0] == '$') { if (!user->HasPrivPermission("users/mass-message")) return CMD_SUCCESS; int MOD_RESULT = 0; std::string temp = parameters[1]; FOREACH_RESULT(I_OnUserPreNotice,OnUserPreNotice(user, (void*)parameters[0].c_str(), TYPE_SERVER, temp, 0, exempt_list)); if (MOD_RESULT) return CMD_FAILURE; const char* text = temp.c_str(); const char* servermask = (parameters[0].c_str()) + 1; FOREACH_MOD(I_OnText,OnText(user, (void*)parameters[0].c_str(), TYPE_SERVER, text, 0, exempt_list)); if (InspIRCd::Match(ServerInstance->Config->ServerName,servermask, NULL)) { user->SendAll("NOTICE", "%s", text); } FOREACH_MOD(I_OnUserNotice,OnUserNotice(user, (void*)parameters[0].c_str(), TYPE_SERVER, text, 0, exempt_list)); return CMD_SUCCESS; } char status = 0; const char* target = parameters[0].c_str(); if (ServerInstance->Modes->FindPrefix(*target)) { status = *target; target++; } if (*target == '#') { chan = ServerInstance->FindChan(target); exempt_list[user] = user->nick; if (chan) { if (IS_LOCAL(user)) { if ((chan->IsModeSet('n')) && (!chan->HasUser(user))) { user->WriteNumeric(404, "%s %s :Cannot send to channel (no external messages)", user->nick.c_str(), chan->name.c_str()); return CMD_FAILURE; } if ((chan->IsModeSet('m')) && (chan->GetStatus(user) < STATUS_VOICE)) { user->WriteNumeric(404, "%s %s :Cannot send to channel (+m)", user->nick.c_str(), chan->name.c_str()); return CMD_FAILURE; } } int MOD_RESULT = 0; std::string temp = parameters[1]; FOREACH_RESULT(I_OnUserPreNotice,OnUserPreNotice(user,chan,TYPE_CHANNEL,temp,status, exempt_list)); if (MOD_RESULT) { return CMD_FAILURE; } const char* text = temp.c_str(); if (temp.empty()) { user->WriteNumeric(412, "%s :No text to send", user->nick.c_str()); return CMD_FAILURE; } FOREACH_MOD(I_OnText,OnText(user,chan,TYPE_CHANNEL,text,status,exempt_list)); if (status) { if (ServerInstance->Config->UndernetMsgPrefix) { chan->WriteAllExcept(user, false, status, exempt_list, "NOTICE %c%s :%c %s", status, chan->name.c_str(), status, text); } else { chan->WriteAllExcept(user, false, status, exempt_list, "NOTICE %c%s :%s", status, chan->name.c_str(), text); } } else { chan->WriteAllExcept(user, false, status, exempt_list, "NOTICE %s :%s", chan->name.c_str(), text); } FOREACH_MOD(I_OnUserNotice,OnUserNotice(user,chan,TYPE_CHANNEL,text,status,exempt_list)); } else { /* no such nick/channel */ user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), target); return CMD_FAILURE; } return CMD_SUCCESS; } const char* destnick = parameters[0].c_str(); if (IS_LOCAL(user)) { const char* targetserver = strchr(destnick, '@'); if (targetserver) { std::string nickonly; nickonly.assign(destnick, 0, targetserver - destnick); dest = ServerInstance->FindNickOnly(nickonly); if (dest && strcasecmp(dest->server, targetserver + 1)) { /* Incorrect server for user */ user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str()); return CMD_FAILURE; } } else dest = ServerInstance->FindNickOnly(destnick); } else dest = ServerInstance->FindNick(destnick); if (dest) { if (parameters[1].empty()) { user->WriteNumeric(412, "%s :No text to send", user->nick.c_str()); return CMD_FAILURE; } int MOD_RESULT = 0; std::string temp = parameters[1]; FOREACH_RESULT(I_OnUserPreNotice,OnUserPreNotice(user,dest,TYPE_USER,temp,0,exempt_list)); if (MOD_RESULT) { return CMD_FAILURE; } const char* text = temp.c_str(); FOREACH_MOD(I_OnText,OnText(user,dest,TYPE_USER,text,0,exempt_list)); if (IS_LOCAL(dest)) { // direct write, same server user->WriteTo(dest, "NOTICE %s :%s", dest->nick.c_str(), text); } FOREACH_MOD(I_OnUserNotice,OnUserNotice(user,dest,TYPE_USER,text,0,exempt_list)); } else { /* no such nick/channel */ user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str()); return CMD_FAILURE; } return CMD_SUCCESS; }
void DoAdd(CommandSource &source, const std::vector<Anope::string> ¶ms) { User *u = source.u; Anope::string mask, expiry, limitstr; unsigned last_param = 3; mask = params.size() > 1 ? params[1] : ""; if (!mask.empty() && mask[0] == '+') { expiry = mask; mask = params.size() > 2 ? params[2] : ""; last_param = 4; } limitstr = params.size() > last_param - 1 ? params[last_param - 1] : ""; if (params.size() <= last_param) { this->OnSyntaxError(source, "ADD"); return; } Anope::string reason = params[last_param]; if (last_param == 3 && params.size() > 4) reason += " " + params[4]; if (reason.empty()) { this->OnSyntaxError(source, "ADD"); return; } time_t expires = !expiry.empty() ? dotime(expiry) : Config->ExceptionExpiry; if (expires < 0) { source.Reply(BAD_EXPIRY_TIME); return; } else if (expires > 0) expires += Anope::CurTime; int limit = -1; try { limit = convertTo<int>(limitstr); } catch (const ConvertException &) { } if (limit < 0 || limit > static_cast<int>(Config->MaxSessionLimit)) { source.Reply(_("Invalid session limit. It must be a valid integer greater than or equal to zero and less than \002%d\002."), Config->MaxSessionLimit); return; } else { if (mask.find('!') != Anope::string::npos || mask.find('@') != Anope::string::npos) { source.Reply(_("Invalid hostmask. Only real hostmasks are valid, as exceptions are not matched against nicks or usernames.")); return; } for (std::vector<Exception *>::iterator it = session_service->GetExceptions().begin(), it_end = session_service->GetExceptions().end(); it != it_end; ++it) { Exception *e = *it; if (e->mask.equals_ci(mask)) { if (e->limit != limit) { e->limit = limit; source.Reply(_("Exception for \002%s\002 has been updated to %d."), mask.c_str(), e->limit); } else source.Reply(_("\002%s\002 already exists on the EXCEPTION list."), mask.c_str()); return; } } Exception *exception = new Exception(); exception->mask = mask; exception->limit = limit; exception->reason = reason; exception->time = Anope::CurTime; exception->who = u->nick; exception->expires = expires; EventReturn MOD_RESULT; FOREACH_RESULT(I_OnExceptionAdd, OnExceptionAdd(exception)); if (MOD_RESULT == EVENT_STOP) delete exception; else { session_service->AddException(exception); source.Reply(_("Session limit for \002%s\002 set to \002%d\002."), mask.c_str(), limit); if (readonly) source.Reply(READ_ONLY_MODE); } } return; }
/** Handle nick changes from users. * NOTE: If you are used to ircds based on ircd2.8, and are looking * for the client introduction code in here, youre in the wrong place. * You need to look in the spanningtree module for this! */ CmdResult CommandNick::Handle (const std::vector<std::string>& parameters, User *user) { std::string oldnick; if (parameters[0].empty()) { /* We cant put blanks in the parameters, so for this (extremely rare) issue we just put '*' here. */ user->WriteNumeric(432, "%s * :Erroneous Nickname", user->nick.empty() ? user->nick.c_str() : "*"); return CMD_FAILURE; } if (((!ServerInstance->IsNick(parameters[0].c_str(), ServerInstance->Config->Limits.NickMax))) && (IS_LOCAL(user))) { if (!allowinvalid) { if (parameters[0] == "0") { // Special case, Fake a /nick UIDHERE. Useful for evading "ERR: NICK IN USE" on connect etc. std::vector<std::string> p2; std::deque<classbase*> dummy; p2.push_back(user->uuid); this->HandleInternal(1, dummy); this->Handle(p2, user); this->HandleInternal(0, dummy); return CMD_SUCCESS; } user->WriteNumeric(432, "%s %s :Erroneous Nickname", user->nick.c_str(),parameters[0].c_str()); return CMD_FAILURE; } } if (assign(user->nick) == parameters[0]) { /* If its exactly the same, even case, dont do anything. */ if (parameters[0] == user->nick) { return CMD_SUCCESS; } /* Its a change of case. People insisted that they should be * able to do silly things like this even though the RFC says * the nick AAA is the same as the nick aaa. */ oldnick.assign(user->nick, 0, IS_LOCAL(user) ? ServerInstance->Config->Limits.NickMax : MAXBUF); int MOD_RESULT = 0; FOREACH_RESULT(I_OnUserPreNick,OnUserPreNick(user,parameters[0])); if (MOD_RESULT) return CMD_FAILURE; if (user->registered == REG_ALL) user->WriteCommon("NICK %s",parameters[0].c_str()); user->nick.assign(parameters[0], 0, IS_LOCAL(user) ? ServerInstance->Config->Limits.NickMax : MAXBUF); user->InvalidateCache(); FOREACH_MOD(I_OnUserPostNick,OnUserPostNick(user,oldnick)); return CMD_SUCCESS; } else { /* * Don't check Q:Lines if it's a server-enforced change, just on the off-chance some f*****g *moron* * tries to Q:Line SIDs, also, this means we just get our way period, as it really should be. * Thanks Kein for finding this. -- w00t * * Also don't check Q:Lines for remote nickchanges, they should have our Q:Lines anyway to enforce themselves. * -- w00t */ if (!allowinvalid || !IS_LOCAL(user)) { XLine* mq = ServerInstance->XLines->MatchesLine("Q",parameters[0]); if (mq) { if (user->registered == REG_ALL) { ServerInstance->SNO->WriteToSnoMask('x', "Q-Lined nickname %s from %s!%s@%s: %s", parameters[0].c_str(), user->nick.c_str(), user->ident.c_str(), user->host.c_str(), mq->reason); } user->WriteNumeric(432, "%s %s :Invalid nickname: %s",user->nick.c_str(), parameters[0].c_str(), mq->reason); return CMD_FAILURE; } if (ServerInstance->Config->RestrictBannedUsers) { for (UCListIter i = user->chans.begin(); i != user->chans.end(); i++) { Channel *chan = i->first; if (chan->GetStatus(user) < STATUS_VOICE && chan->IsBanned(user)) { user->WriteNumeric(404, "%s %s :Cannot send to channel (you're banned)", user->nick.c_str(), chan->name.c_str()); return CMD_FAILURE; } } } } /* * 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(parameters[0]); if (InUse && (InUse != user)) { if (InUse->registered != REG_ALL) { /* force the camper to their UUID, and ask them to re-send a NICK. */ InUse->WriteTo(InUse, "NICK %s", InUse->uuid.c_str()); InUse->WriteNumeric(433, "%s %s :Nickname overruled.", InUse->nick.c_str(), InUse->nick.c_str()); InUse->UpdateNickHash(InUse->uuid.c_str()); InUse->nick.assign(InUse->uuid, 0, IS_LOCAL(InUse) ? ServerInstance->Config->Limits.NickMax : MAXBUF); InUse->InvalidateCache(); InUse->registered &= ~REG_NICK; } else { /* No camping, tell the incoming user to stop trying to change nick ;p */ user->WriteNumeric(433, "%s %s :Nickname is already in use.", user->registered >= REG_NICK ? user->nick.c_str() : "*", parameters[0].c_str()); return CMD_FAILURE; } } } int MOD_RESULT = 0; FOREACH_RESULT(I_OnUserPreNick,OnUserPreNick(user, parameters[0])); if (MOD_RESULT) // if a module returns true, the nick change is silently forbidden. return CMD_FAILURE; if (user->registered == REG_ALL) user->WriteCommon("NICK %s", parameters[0].c_str()); oldnick.assign(user->nick, 0, IS_LOCAL(user) ? ServerInstance->Config->Limits.NickMax : MAXBUF); /* change the nick of the user in the users_hash */ user = user->UpdateNickHash(parameters[0].c_str()); /* actually change the nick within the record */ if (!user) return CMD_FAILURE; user->nick.assign(parameters[0], 0, IS_LOCAL(user) ? ServerInstance->Config->Limits.NickMax : MAXBUF); user->InvalidateCache(); /* Update display nicks */ for (UCListIter v = user->chans.begin(); v != user->chans.end(); v++) { CUList* ulist = v->first->GetUsers(); CUList::iterator i = ulist->find(user); if (i != ulist->end()) i->second = user->nick; } if (user->registered < REG_NICKUSER) { user->registered = (user->registered | REG_NICK); if (user->registered == REG_NICKUSER) { /* user is registered now, bit 0 = USER command, bit 1 = sent a NICK command */ MOD_RESULT = 0; FOREACH_RESULT(I_OnUserRegister,OnUserRegister(user)); if (MOD_RESULT > 0) return CMD_FAILURE; // return early to not penalize new users return CMD_SUCCESS; } } if (user->registered == REG_ALL) { user->IncreasePenalty(10); FOREACH_MOD(I_OnUserPostNick,OnUserPostNick(user, oldnick)); } return CMD_SUCCESS; }
bool IRCdMessage::OnPrivmsg(const Anope::string &source, const std::vector<Anope::string> ¶ms) { const Anope::string &receiver = params.size() > 0 ? params[0] : ""; Anope::string message = params.size() > 1 ? params[1] : ""; /* Messages from servers can happen on some IRCds, check for . */ if (source.empty() || receiver.empty() || message.empty() || source.find('.') != Anope::string::npos) return true; User *u = finduser(source); if (!u) { Log() << message << ": user record for " << source << " not found"; BotInfo *bi = findbot(receiver); if (bi) ircdproto->SendMessage(bi, source, "%s", "Internal error - unable to process request."); return true; } if (receiver[0] == '#') { Channel *c = findchan(receiver); if (c) { FOREACH_MOD(I_OnPrivmsg, OnPrivmsg(u, c, message)); } } else { /* If a server is specified (nick@server format), make sure it matches * us, and strip it off. */ Anope::string botname = receiver; size_t s = receiver.find('@'); if (s != Anope::string::npos) { Anope::string servername(receiver.begin() + s + 1, receiver.end()); botname = botname.substr(0, s); if (!servername.equals_ci(Config->ServerName)) return true; } else if (Config->UseStrictPrivMsg) { BotInfo *bi = findbot(receiver); if (!bi) return true; Log(LOG_DEBUG) << "Ignored PRIVMSG without @ from " << source; u->SendMessage(bi, _("\"/msg %s\" is no longer supported. Use \"/msg %s@%s\" or \"/%s\" instead."), receiver.c_str(), receiver.c_str(), Config->ServerName.c_str(), receiver.c_str()); return true; } BotInfo *bi = findbot(botname); if (bi) { EventReturn MOD_RESULT; FOREACH_RESULT(I_OnBotPrivmsg, OnBotPrivmsg(u, bi, message)); if (MOD_RESULT == EVENT_STOP) return true; if (message[0] == '\1' && message[message.length() - 1] == '\1') { if (message.substr(0, 6).equals_ci("\1PING ")) { Anope::string buf = message; buf.erase(buf.begin()); buf.erase(buf.end() - 1); ircdproto->SendCTCP(bi, u->nick, "%s", buf.c_str()); } else if (message.substr(0, 9).equals_ci("\1VERSION\1")) { Module *enc = ModuleManager::FindFirstOf(ENCRYPTION); ircdproto->SendCTCP(bi, u->nick, "VERSION Anope-%s %s :%s - (%s) -- %s", Anope::Version().c_str(), Config->ServerName.c_str(), ircd->name, enc ? enc->name.c_str() : "unknown", Anope::VersionBuildString().c_str()); } return true; } bi->OnMessage(u, message); } } return true; }
bool OnSJoin(const Anope::string &source, const std::vector<Anope::string> ¶ms) { Channel *c = findchan(params[1]); time_t ts = Anope::string(params[0]).is_pos_number_only() ? convertTo<time_t>(params[0]) : 0; bool keep_their_modes = true; if (!c) { c = new Channel(params[1], ts); c->SetFlag(CH_SYNCING); } /* Our creation time is newer than what the server gave us */ else if (c->creation_time > ts) { c->creation_time = ts; c->Reset(); } /* Their TS is newer than ours, our modes > theirs, unset their modes if need be */ else if (ts > c->creation_time) keep_their_modes = false; /* If we need to keep their modes, and this SJOIN string contains modes */ if (keep_their_modes && params.size() >= 4) { /* Set the modes internally */ Anope::string modes; for (unsigned i = 2; i < params.size(); ++i) modes += " " + params[i]; if (!modes.empty()) modes.erase(modes.begin()); c->SetModesInternal(NULL, modes); } /* For some reason, bahamut will send a SJOIN from the user joining a channel * if the channel already existed */ if (!c->HasFlag(CH_SYNCING) && params.size() == 2) { User *u = finduser(source); if (!u) Log(LOG_DEBUG) << "SJOIN for nonexistant user " << source << " on " << c->name; else { EventReturn MOD_RESULT; FOREACH_RESULT(I_OnPreJoinChannel, OnPreJoinChannel(u, c)); /* Add the user to the channel */ c->JoinUser(u); /* Now set whatever modes this user is allowed to have on the channel */ chan_set_correct_modes(u, c, 1); /* Check to see if modules want the user to join, if they do * check to see if they are allowed to join (CheckKick will kick/ban them) * Don't trigger OnJoinChannel event then as the user will be destroyed */ if (MOD_RESULT == EVENT_STOP && (!c->ci || !c->ci->CheckKick(u))) { FOREACH_MOD(I_OnJoinChannel, OnJoinChannel(u, c)); } } } else { spacesepstream sep(params[params.size() - 1]); Anope::string buf; while (sep.GetToken(buf)) { std::list<ChannelMode *> Status; char ch; /* Get prefixes from the nick */ while ((ch = ModeManager::GetStatusChar(buf[0]))) { buf.erase(buf.begin()); ChannelMode *cm = ModeManager::FindChannelModeByChar(ch); if (!cm) { Log() << "Received unknown mode prefix " << cm << " in SJOIN string"; continue; } if (keep_their_modes) Status.push_back(cm); } User *u = finduser(buf); if (!u) { Log(LOG_DEBUG) << "SJOIN for nonexistant user " << buf << " on " << c->name; continue; } EventReturn MOD_RESULT; FOREACH_RESULT(I_OnPreJoinChannel, OnPreJoinChannel(u, c)); /* Add the user to the channel */ c->JoinUser(u); /* Update their status internally on the channel * This will enforce secureops etc on the user */ for (std::list<ChannelMode *>::iterator it = Status.begin(), it_end = Status.end(); it != it_end; ++it) c->SetModeInternal(*it, buf); /* Now set whatever modes this user is allowed to have on the channel */ chan_set_correct_modes(u, c, 1); /* Check to see if modules want the user to join, if they do * check to see if they are allowed to join (CheckKick will kick/ban them) * Don't trigger OnJoinChannel event then as the user will be destroyed */ if (MOD_RESULT != EVENT_STOP && c->ci && c->ci->CheckKick(u)) continue; FOREACH_MOD(I_OnJoinChannel, OnJoinChannel(u, c)); } } /* Channel is done syncing */ if (c->HasFlag(CH_SYNCING)) { /* Unset the syncing flag */ c->UnsetFlag(CH_SYNCING); c->Sync(); } return true; }
/** * \fn Log::~Log() * \brief Logging destructor, this is where the files are actually written and messages are logged */ Log::~Log() { Flux::string LogColor = Config ? Config->LogColor : "\033[0m"; Flux::string message = Flux::Sanitize(this->buffer.str()); std::stringstream logstream; if(this->u && !this->c) message = this->u->nick + " " + message; if(this->u && this->c) message = this->u->nick + " used " + this->c->name + " " + message; EventResult result; FOREACH_RESULT(I_OnLog, OnLog(this), result); if(result != EVENT_CONTINUE) return; switch(type) { case LOG_SILENT: case LOG_NORMAL: logstream << TimeStamp() << " " << message; this->ToFile(logstream); break; case LOG_THREAD: if(protocoldebug) { logstream << TimeStamp() << " [THREAD] " << message; this->ToFile(logstream); } break; case LOG_DEBUG: if(protocoldebug) { logstream << TimeStamp() << " " << message; this->ToFile(logstream); } break; case LOG_DEVEL: if(!protocoldebug && dev) { logstream << TimeStamp() << message; this->ToFile(logstream); } break; case LOG_RAWIO: if(protocoldebug) { logstream << TimeStamp() << " " << message; this->ToFile(logstream); } break; case LOG_CRITICAL: logstream << "\033[22;31m" << TimeStamp() << " [CRITICAL] " << message << LogColor; this->ToFile(logstream); break; case LOG_WARN: logstream << TimeStamp() << " \033[22;33m[WARNING]" << LogColor << " " << message; this->ToFile(logstream); break; case LOG_MEMORY: if(memdebug) std::cout << TimeStamp() << " [MEMORY] " << message << std::endl; return; // ignore everything else, it doesn't matter case LOG_TERMINAL: if(InTerm()) std::cout << this->buffer.str() << std::endl; return; default: Log(LOG_WARN) << "Wtf log case is this?"; Log(LOG_TERMINAL) << "\033[22;33m[UNDEFINED]" << LogColor << " " << message; } }