bahamut.cpp

Go to the documentation of this file.
00001 /* Bahamut functions
00002  *
00003  * (C) 2003-2013 Anope Team
00004  * Contact us at team@anope.org
00005  *
00006  * Please read COPYING and README for further details.
00007  *
00008  * Based on the original code of Epona by Lara.
00009  * Based on the original code of Services by Andy Church.
00010  */
00011 
00012 /*************************************************************************/
00013 
00014 #include "module.h"
00015 
00016 class ChannelModeFlood : public ChannelModeParam
00017 {
00018  public:
00019         ChannelModeFlood(char modeChar, bool minusNoArg) : ChannelModeParam("FLOOD", modeChar, minusNoArg) { }
00020 
00021         bool IsValid(const Anope::string &value) const anope_override
00022         {
00023                 try
00024                 {
00025                         Anope::string rest;
00026                         if (!value.empty() && value[0] != ':' && convertTo<int>(value[0] == '*' ? value.substr(1) : value, rest, false) > 0 && rest[0] == ':' && rest.length() > 1 && convertTo<int>(rest.substr(1), rest, false) > 0 && rest.empty())
00027                                 return true;
00028                 }
00029                 catch (const ConvertException &) { }
00030 
00031                 return false;
00032         }
00033 };
00034 
00035 class BahamutIRCdProto : public IRCDProto
00036 {
00037  public:
00038         BahamutIRCdProto(Module *creator) : IRCDProto(creator, "Bahamut 1.8.x")
00039         {
00040                 DefaultPseudoclientModes = "+";
00041                 CanSVSNick = true;
00042                 CanSNLine = true;
00043                 CanSQLine = true;
00044                 CanSQLineChannel = true;
00045                 CanSZLine = true;
00046                 CanSVSHold = true;
00047                 MaxModes = 60;
00048         }
00049 
00050         void SendModeInternal(const BotInfo *source, const Channel *dest, const Anope::string &buf) anope_override
00051         {
00052                 if (Servers::Capab.count("TSMODE") > 0)
00053                 {
00054                         if (source)
00055                                 UplinkSocket::Message(source) << "MODE " << dest->name << " " << dest->creation_time << " " << buf;
00056                         else
00057                                 UplinkSocket::Message(Me) << "MODE " << dest->name << " " << dest->creation_time << " " << buf;
00058                 }
00059                 else
00060                         IRCDProto::SendModeInternal(source, dest, buf);
00061         }
00062 
00063         void SendModeInternal(const BotInfo *bi, const User *u, const Anope::string &buf) anope_override
00064         {
00065                 if (bi)
00066                         UplinkSocket::Message(bi) << "SVSMODE " << u->nick << " " << u->timestamp << " " << buf;
00067                 else
00068                         UplinkSocket::Message(Me) << "SVSMODE " << u->nick << " " << u->timestamp << " " << buf;
00069         }
00070 
00071         void SendGlobalNotice(const BotInfo *bi, const Server *dest, const Anope::string &msg) anope_override
00072         {
00073                 UplinkSocket::Message(bi) << "NOTICE $" << dest->GetName() << " :" << msg;
00074         }
00075 
00076         void SendGlobalPrivmsg(const BotInfo *bi, const Server *dest, const Anope::string &msg) anope_override
00077         {
00078                 UplinkSocket::Message(bi) << "PRIVMSG $" << dest->GetName() << " :" << msg;
00079         }
00080 
00081         /* SVSHOLD - set */
00082         void SendSVSHold(const Anope::string &nick) anope_override
00083         {
00084                 UplinkSocket::Message(Me) << "SVSHOLD " << nick << " " << Config->NSReleaseTimeout << " :Being held for registered user";
00085         }
00086 
00087         /* SVSHOLD - release */
00088         void SendSVSHoldDel(const Anope::string &nick) anope_override
00089         {
00090                 UplinkSocket::Message(Me) << "SVSHOLD " << nick << " 0";
00091         }
00092 
00093         /* SQLINE */
00094         void SendSQLine(User *, const XLine *x) anope_override
00095         {
00096                 UplinkSocket::Message() << "SQLINE " << x->mask << " :" << x->GetReason();
00097         }
00098 
00099         /* UNSLINE */
00100         void SendSGLineDel(const XLine *x) anope_override
00101         {
00102                 UplinkSocket::Message() << "UNSGLINE 0 :" << x->mask;
00103         }
00104 
00105         /* UNSZLINE */
00106         void SendSZLineDel(const XLine *x) anope_override
00107         {
00108                 /* this will likely fail so its only here for legacy */
00109                 UplinkSocket::Message() << "UNSZLINE 0 " << x->GetHost();
00110                 /* this is how we are supposed to deal with it */
00111                 UplinkSocket::Message() << "RAKILL " << x->GetHost() << " *";
00112         }
00113 
00114         /* SZLINE */
00115         void SendSZLine(User *, const XLine *x) anope_override
00116         {
00117                 // Calculate the time left before this would expire, capping it at 2 days
00118                 time_t timeleft = x->expires - Anope::CurTime;
00119                 if (timeleft > 172800 || !x->expires)
00120                         timeleft = 172800;
00121                 /* this will likely fail so its only here for legacy */
00122                 UplinkSocket::Message() << "SZLINE " << x->GetHost() << " :" << x->GetReason();
00123                 /* this is how we are supposed to deal with it */
00124                 UplinkSocket::Message() << "AKILL " << x->GetHost() << " * " << timeleft << " " << x->by << " " << Anope::CurTime << " :" << x->GetReason();
00125         }
00126 
00127         /* SVSNOOP */
00128         void SendSVSNOOP(const Server *server, bool set) anope_override
00129         {
00130                 UplinkSocket::Message() << "SVSNOOP " << server->GetName() << " " << (set ? "+" : "-");
00131         }
00132 
00133         /* SGLINE */
00134         void SendSGLine(User *, const XLine *x) anope_override
00135         {
00136                 UplinkSocket::Message() << "SGLINE " << x->mask.length() << " :" << x->mask << ":" << x->GetReason();
00137         }
00138 
00139         /* RAKILL */
00140         void SendAkillDel(const XLine *x) anope_override
00141         {
00142                 if (x->IsRegex() || x->HasNickOrReal())
00143                         return;
00144 
00145                 /* ZLine if we can instead */
00146                 try
00147                 {
00148                         if (x->GetUser() == "*")
00149                         {
00150                                 sockaddrs(x->GetHost());
00151                                 IRCD->SendSZLineDel(x);
00152                                 return;
00153                         }
00154                 }
00155                 catch (const SocketException &) { }
00156 
00157                 UplinkSocket::Message() << "RAKILL " << x->GetHost() << " " << x->GetUser();
00158         }
00159 
00160         /* TOPIC */
00161         void SendTopic(BotInfo *whosets, Channel *c) anope_override
00162         {
00163                 UplinkSocket::Message(whosets) << "TOPIC " << c->name << " " << c->topic_setter << " " << c->topic_ts << " :" << c->topic;
00164         }
00165 
00166         /* UNSQLINE */
00167         void SendSQLineDel(const XLine *x) anope_override
00168         {
00169                 UplinkSocket::Message() << "UNSQLINE " << x->mask;
00170         }
00171 
00172         /* JOIN - SJOIN */
00173         void SendJoin(const User *user, Channel *c, const ChannelStatus *status) anope_override
00174         {
00175                 UplinkSocket::Message(user) << "SJOIN " << c->creation_time << " " << c->name;
00176                 if (status)
00177                 {
00178                         /* First save the channel status incase uc->Status == status */
00179                         ChannelStatus cs = *status;
00180                         /* If the user is internally on the channel with flags, kill them so that
00181                          * the stacker will allow this.
00182                          */
00183                         ChanUserContainer *uc = c->FindUser(user);
00184                         if (uc != NULL)
00185                                 uc->status.modes.clear();
00186 
00187                         BotInfo *setter = BotInfo::Find(user->nick);
00188                         for (unsigned i = 0; i < ModeManager::ChannelModes.size(); ++i)
00189                                 if (cs.modes.count(ModeManager::ChannelModes[i]->name))
00190                                         c->SetMode(setter, ModeManager::ChannelModes[i], user->GetUID(), false);
00191                 }
00192         }
00193 
00194         void SendAkill(User *u, XLine *x) anope_override
00195         {
00196                 if (x->IsRegex() || x->HasNickOrReal())
00197                 {
00198                         if (!u)
00199                         {
00200                                 /* No user (this akill was just added), and contains nick and/or realname. Find users that match and ban them */
00201                                 for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it)
00202                                         if (x->manager->Check(it->second, x))
00203                                                 this->SendAkill(it->second, x);
00204                                 return;
00205                         }
00206 
00207                         const XLine *old = x;
00208 
00209                         if (old->manager->HasEntry("*@" + u->host))
00210                                 return;
00211 
00212                         /* We can't akill x as it has a nick and/or realname included, so create a new akill for *@host */
00213                         x = new XLine("*@" + u->host, old->by, old->expires, old->reason, old->id);
00214                         old->manager->AddXLine(x);
00215 
00216                         Log(OperServ, "akill") << "AKILL: Added an akill for " << x->mask << " because " << u->GetMask() << "#" << u->realname << " matches " << old->mask;
00217                 }
00218 
00219                 /* ZLine if we can instead */
00220                 try
00221                 {
00222                         if (x->GetUser() == "*")
00223                         {
00224                                 sockaddrs(x->GetHost());
00225                                 IRCD->SendSZLine(u, x);
00226                                 return;
00227                         }
00228                 }
00229                 catch (const SocketException &) { }
00230 
00231                 // Calculate the time left before this would expire, capping it at 2 days
00232                 time_t timeleft = x->expires - Anope::CurTime;
00233                 if (timeleft > 172800)
00234                         timeleft = 172800;
00235                 UplinkSocket::Message() << "AKILL " << x->GetHost() << " " << x->GetUser() << " " << timeleft << " " << x->by << " " << Anope::CurTime << " :" << x->GetReason();
00236         }
00237 
00238         /*
00239           Note: if the stamp is null 0, the below usage is correct of Bahamut
00240         */
00241         void SendSVSKillInternal(const BotInfo *source, User *user, const Anope::string &buf) anope_override
00242         {
00243                 if (source)
00244                         UplinkSocket::Message(source) << "SVSKILL " << user->nick << " :" << buf;
00245                 else
00246                         UplinkSocket::Message() << "SVSKILL " << user->nick << " :" << buf;
00247         }
00248 
00249         void SendBOB() anope_override
00250         {
00251                 UplinkSocket::Message() << "BURST";
00252         }
00253 
00254         void SendEOB() anope_override
00255         {
00256                 UplinkSocket::Message() << "BURST 0";
00257         }
00258 
00259         void SendClientIntroduction(const User *u) anope_override
00260         {
00261                 Anope::string modes = "+" + u->GetModes();
00262                 UplinkSocket::Message() << "NICK " << u->nick << " 1 " << u->timestamp << " " << modes << " " << u->GetIdent() << " " << u->host << " " << u->server->GetName() << " 0 0 :" << u->realname;
00263         }
00264 
00265         /* SERVER */
00266         void SendServer(const Server *server) anope_override
00267         {
00268                 UplinkSocket::Message() << "SERVER " << server->GetName() << " " << server->GetHops() << " :" << server->GetDescription();
00269         }
00270 
00271         void SendConnect() anope_override
00272         {
00273                 UplinkSocket::Message() << "PASS " << Config->Uplinks[Anope::CurrentUplink]->password << " :TS";
00274                 UplinkSocket::Message() << "CAPAB SSJOIN NOQUIT BURST UNCONNECT NICKIP TSMODE TS3";
00275                 SendServer(Me);
00276                 /*
00277                  * SVINFO
00278                  *         parv[0] = sender prefix
00279                  *         parv[1] = TS_CURRENT for the server
00280                  *         parv[2] = TS_MIN for the server
00281                  *         parv[3] = server is standalone or connected to non-TS only
00282                  *         parv[4] = server's idea of UTC time
00283                  */
00284                 UplinkSocket::Message() << "SVINFO 3 1 0 :" << Anope::CurTime;
00285                 this->SendBOB();
00286         }
00287 
00288         void SendChannel(Channel *c) anope_override
00289         {
00290                 Anope::string modes = c->GetModes(true, true);
00291                 if (modes.empty())
00292                         modes = "+";
00293                 UplinkSocket::Message() << "SJOIN " << c->creation_time << " " << c->name << " " << modes << " :";
00294         }
00295 
00296         void SendLogin(User *u) anope_override
00297         {
00298                 IRCD->SendMode(NickServ, u, "+d %d", u->signon);
00299         }
00300 
00301         void SendLogout(User *u) anope_override
00302         {
00303                 IRCD->SendMode(NickServ, u, "+d 1");
00304         }
00305 };
00306 
00307 struct IRCDMessageBurst : IRCDMessage
00308 {
00309         IRCDMessageBurst(Module *creator) : IRCDMessage(creator, "BURST", 0) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); SetFlag(IRCDMESSAGE_SOFT_LIMIT); }
00310 
00311         void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00312         {
00313                 /* If we found a server with the given source, that one just
00314                  * finished bursting. If there was no source, then our uplink
00315                  * server finished bursting. -GD
00316                  */
00317                 Server *s = source.GetServer();
00318                 if (!s)
00319                         s = Me->GetLinks().front();
00320                 if (s)
00321                         s->Sync(true);
00322         }
00323 };
00324 
00325 struct IRCDMessageMode : IRCDMessage
00326 {
00327         IRCDMessageMode(Module *creator, const Anope::string &sname) : IRCDMessage(creator, sname, 2) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); }
00328 
00329         void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00330         {
00331                 if (params.size() > 2 && IRCD->IsChannelValid(params[0]))
00332                 {
00333                         Channel *c = Channel::Find(params[0]);
00334                         time_t ts = 0;
00335 
00336                         try
00337                         {
00338                                 ts = convertTo<time_t>(params[1]);
00339                         }
00340                         catch (const ConvertException &) { }
00341 
00342                         if (c)
00343                                 c->SetModesInternal(source, params[2], ts);
00344                 }
00345                 else
00346                 {
00347                         User *u = User::Find(params[0]);
00348                         if (u)
00349                                 u->SetModesInternal("%s", params[1].c_str());
00350                 }
00351         }
00352 };
00353 
00354 /*
00355  ** NICK - new
00356  **       source  = NULL
00357  **       parv[0] = nickname
00358  **       parv[1] = hopcount
00359  **       parv[2] = timestamp
00360  **       parv[3] = modes
00361  **       parv[4] = username
00362  **       parv[5] = hostname
00363  **       parv[6] = server
00364  **       parv[7] = servicestamp
00365  **       parv[8] = IP
00366  **       parv[9] = info
00367  ** NICK - change
00368  **       source  = oldnick
00369  **       parv[0] = new nickname
00370  **       parv[1] = hopcount
00371  */
00372 struct IRCDMessageNick : IRCDMessage
00373 {
00374         ServiceReference<NickServService> NSService;
00375 
00376         IRCDMessageNick(Module *creator) : IRCDMessage(creator, "NICK", 2), NSService("NickServService", "NickServ") { SetFlag(IRCDMESSAGE_SOFT_LIMIT); }
00377 
00378         void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00379         {
00380                 if (params.size() == 10)
00381                 {
00382                         Server *s = Server::Find(params[6]);
00383                         if (s == NULL)
00384                         {
00385                                 Log(LOG_DEBUG) << "User " << params[0] << " introduced from nonexistant server " << params[6] << "?";
00386                                 return;
00387                         }
00388 
00389                         User *user = new User(params[0], params[4], params[5], "", params[8], s, params[9], params[2].is_pos_number_only() ? convertTo<time_t>(params[2]) : 0, params[3]);
00390                         try
00391                         {
00392                                 NickAlias *na;
00393                                 if (NSService && user->signon == convertTo<time_t>(params[7]) && (na = NickAlias::Find(user->nick)))
00394                                         NSService->Login(user, na);
00395                         }
00396                         catch (const ConvertException &) { }
00397                 }
00398                 else
00399                         source.GetUser()->ChangeNick(params[0]);
00400         }
00401 };
00402 
00403 struct IRCDMessageServer : IRCDMessage
00404 {
00405         IRCDMessageServer(Module *creator) : IRCDMessage(creator, "SERVER", 3) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); }
00406 
00407         void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00408         {
00409                 unsigned int hops = Anope::string(params[1]).is_pos_number_only() ? convertTo<unsigned>(params[1]) : 0;
00410                 new Server(source.GetServer() == NULL ? Me : source.GetServer(), params[0], hops, params[2]);
00411         }
00412 };
00413 
00414 struct IRCDMessageSJoin : IRCDMessage
00415 {
00416         IRCDMessageSJoin(Module *creator) : IRCDMessage(creator, "SJOIN", 2) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); }
00417 
00418         void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
00419         {
00420                 Anope::string modes;
00421                 if (params.size() >= 4)
00422                         for (unsigned i = 2; i < params.size(); ++i)
00423                                 modes += " " + params[i];
00424                 if (!modes.empty())
00425                         modes.erase(modes.begin());
00426 
00427                 std::list<Message::Join::SJoinUser> users;
00428 
00429                 /* For some reason, bahamut will send a SJOIN from the user joining a channel
00430                  * if the channel already existed
00431                  */
00432                 if (source.GetUser())
00433                 {
00434                         Message::Join::SJoinUser sju;
00435                         sju.second = source.GetUser();
00436                         users.push_back(sju);
00437                 }
00438                 else
00439                 {
00440                         spacesepstream sep(params[params.size() - 1]);
00441                         Anope::string buf;
00442 
00443                         while (sep.GetToken(buf))
00444                         {
00445                                 Message::Join::SJoinUser sju;
00446 
00447                                 /* Get prefixes from the nick */
00448                                 for (char ch; (ch = ModeManager::GetStatusChar(buf[0]));)
00449                                 {
00450                                         buf.erase(buf.begin());
00451                                         ChannelMode *cm = ModeManager::FindChannelModeByChar(ch);
00452                                         if (!cm)
00453                                         {
00454                                                 Log() << "Received unknown mode prefix " << cm << " in SJOIN string";
00455                                                 continue;
00456                                         }
00457 
00458                                         sju.first.modes.insert(cm->name);
00459                                 }
00460 
00461                                 sju.second = User::Find(buf);
00462                                 if (!sju.second)
00463                                 {
00464                                         Log(LOG_DEBUG) << "SJOIN for nonexistant user " << buf << " on " << params[1];
00465                                         continue;
00466                                 }
00467 
00468                                 users.push_back(sju);
00469                         }
00470                 }
00471 
00472                 time_t ts = Anope::string(params[0]).is_pos_number_only() ? convertTo<time_t>(params[0]) : Anope::CurTime;
00473                 Message::Join::SJoin(source, params[1], ts, modes, users);
00474         }
00475 };
00476 
00477 struct IRCDMessageTopic : IRCDMessage
00478 {
00479         IRCDMessageTopic(Module *creator) : IRCDMessage(creator, "TOPIC", 4) { }
00480 
00481         void Run(MessageSource &, const std::vector<Anope::string> &params) anope_override
00482         {
00483                 Channel *c = Channel::Find(params[0]);
00484                 if (c)
00485                         c->ChangeTopicInternal(params[1], params[3], Anope::string(params[2]).is_pos_number_only() ? convertTo<time_t>(params[2]) : Anope::CurTime);
00486         }
00487 };
00488 
00489 class ProtoBahamut : public Module
00490 {
00491         BahamutIRCdProto ircd_proto;
00492 
00493         /* Core message handlers */
00494         Message::Away message_away;
00495         Message::Capab message_capab;
00496         Message::Error message_error;
00497         Message::Join message_join;
00498         Message::Kick message_kick;
00499         Message::Kill message_kill;
00500         Message::MOTD message_motd;
00501         Message::Part message_part;
00502         Message::Ping message_ping;
00503         Message::Privmsg message_privmsg;
00504         Message::Quit message_quit;
00505         Message::SQuit message_squit;
00506         Message::Stats message_stats;
00507         Message::Time message_time;
00508         Message::Version message_version;
00509         Message::Whois message_whois;
00510 
00511         /* Our message handlers */
00512         IRCDMessageBurst message_burst;
00513         IRCDMessageMode message_mode, message_svsmode;
00514         IRCDMessageNick message_nick;
00515         IRCDMessageServer message_server;
00516         IRCDMessageSJoin message_sjoin;
00517         IRCDMessageTopic message_topic;
00518 
00519         void AddModes()
00520         {
00521                 /* Add user modes */
00522                 ModeManager::AddUserMode(new UserMode("SERV_ADMIN", 'A'));
00523                 ModeManager::AddUserMode(new UserMode("REGPRIV", 'R'));
00524                 ModeManager::AddUserMode(new UserMode("ADMIN", 'a'));
00525                 ModeManager::AddUserMode(new UserMode("INVIS", 'i'));
00526                 ModeManager::AddUserMode(new UserMode("OPER", 'o'));
00527                 ModeManager::AddUserMode(new UserMode("REGISTERED", 'r'));
00528                 ModeManager::AddUserMode(new UserMode("SNOMASK", 's'));
00529                 ModeManager::AddUserMode(new UserMode("WALLOPS", 'w'));
00530                 ModeManager::AddUserMode(new UserMode("DEAF", 'd'));
00531 
00532                 /* b/e/I */
00533                 ModeManager::AddChannelMode(new ChannelModeList("BAN", 'b'));
00534 
00535                 /* v/h/o/a/q */
00536                 ModeManager::AddChannelMode(new ChannelModeStatus("VOICE", 'v', '+', 0));
00537                 ModeManager::AddChannelMode(new ChannelModeStatus("OP", 'o', '@', 1));
00538 
00539                 /* Add channel modes */
00540                 ModeManager::AddChannelMode(new ChannelMode("BLOCKCOLOR", 'c'));
00541                 ModeManager::AddChannelMode(new ChannelMode("INVITE", 'i'));
00542                 ModeManager::AddChannelMode(new ChannelModeFlood('f', false));
00543                 ModeManager::AddChannelMode(new ChannelModeKey('k'));
00544                 ModeManager::AddChannelMode(new ChannelModeParam("LIMIT", 'l'));
00545                 ModeManager::AddChannelMode(new ChannelMode("MODERATED", 'm'));
00546                 ModeManager::AddChannelMode(new ChannelMode("NOEXTERNAL", 'n'));
00547                 ModeManager::AddChannelMode(new ChannelMode("PRIVATE", 'p'));
00548                 ModeManager::AddChannelMode(new ChannelModeRegistered('r'));
00549                 ModeManager::AddChannelMode(new ChannelMode("SECRET", 's'));
00550                 ModeManager::AddChannelMode(new ChannelMode("TOPIC", 't'));
00551                 ModeManager::AddChannelMode(new ChannelMode("REGMODERATED", 'M'));
00552                 ModeManager::AddChannelMode(new ChannelModeOper('O'));
00553                 ModeManager::AddChannelMode(new ChannelMode("REGISTEREDONLY", 'R'));
00554         }
00555 
00556  public:
00557         ProtoBahamut(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, PROTOCOL),
00558                 ircd_proto(this),
00559                 message_away(this), message_capab(this), message_error(this), message_join(this),
00560                 message_kick(this), message_kill(this), message_motd(this), message_part(this),
00561                 message_ping(this), message_privmsg(this), message_quit(this), message_squit(this),
00562                 message_stats(this), message_time(this), message_version(this), message_whois(this),
00563 
00564                 message_burst(this), message_mode(this, "MODE"), message_svsmode(this, "SVSMODE"),
00565                 message_nick(this), message_server(this), message_sjoin(this), message_topic(this)
00566         {
00567                 this->SetAuthor("Anope");
00568 
00569                 this->AddModes();
00570 
00571                 ModuleManager::Attach(I_OnUserNickChange, this);
00572         }
00573 
00574         void OnUserNickChange(User *u, const Anope::string &) anope_override
00575         {
00576                 u->RemoveModeInternal(ModeManager::FindUserModeByName("REGISTERED"));
00577                 IRCD->SendLogout(u);
00578         }
00579 };
00580 
00581 MODULE_INIT(ProtoBahamut)