/* Bahamut functions * * (C) 2003-2009 Anope Team * Contact us at team@anope.org * * Please read COPYING and README for further details. * * Based on the original code of Epona by Lara. * Based on the original code of Services by Andy Church. * * */ /*************************************************************************/ #include "services.h" #include "pseudo.h" IRCDVar myIrcd[] = { {"Bahamut 1.8.x", /* ircd name */ "+", /* Modes used by pseudoclients */ 2, /* Chan Max Symbols */ "+o", /* Channel Umode used by Botserv bots */ 1, /* SVSNICK */ 0, /* Vhost */ "-r+d", /* Mode on UnReg */ 1, /* Supports SGlines */ 1, /* Supports SQlines */ 1, /* Supports SZlines */ 3, /* Number of server args */ 0, /* Join 2 Set */ 0, /* Join 2 Message */ 0, /* TS Topic Forward */ 0, /* TS Topci Backward */ 1, /* Chan SQlines */ 1, /* Quit on Kill */ 1, /* SVSMODE unban */ 0, /* Reverse */ 0, /* vidents */ 1, /* svshold */ 1, /* time stamp on mode */ 1, /* NICKIP */ 0, /* O:LINE */ 1, /* UMODE */ 0, /* VHOST ON NICK */ 0, /* Change RealName */ 0, 1, 1, /* No Knock requires +i */ NULL, /* CAPAB Chan Modes */ 0, /* We support TOKENS */ 0, /* TIME STAMPS are BASE64 */ 0, /* SJOIN ban char */ 0, /* SJOIN except char */ 0, /* SJOIN invite char */ 0, /* Can remove User Channel Modes with SVSMODE */ 0, /* Sglines are not enforced until user reconnects */ 0, /* ts6 */ 0, /* p10 */ NULL, /* character set */ 0, /* CIDR channelbans */ "$", /* TLD Prefix for Global */ false, /* Auth for users is sent after the initial NICK/UID command */ } , {NULL} }; IRCDCAPAB myIrcdcap[] = { { CAPAB_NOQUIT, /* NOQUIT */ CAPAB_TSMODE, /* TSMODE */ CAPAB_UNCONNECT, /* UNCONNECT */ 0, /* NICKIP */ 0, /* SJOIN */ 0, /* ZIP */ CAPAB_BURST, /* BURST */ 0, /* TS5 */ 0, /* TS3 */ CAPAB_DKEY, /* DKEY */ 0, /* PT4 */ 0, /* SCS */ 0, /* QS */ 0, /* UID */ 0, /* KNOCK */ 0, /* CLIENT */ 0, /* IPV6 */ 0, /* SSJ5 */ 0, /* SN2 */ 0, /* TOKEN */ 0, /* VHOST */ 0, /* SSJ3 */ 0, /* NICK2 */ 0, /* VL */ 0, /* TLKEXT */ 0, /* DODKEY */ CAPAB_DOZIP, /* DOZIP */ 0, 0, 0} }; void bahamut_cmd_burst() { send_cmd(NULL, "BURST"); } /* * SVINFO * parv[0] = sender prefix * parv[1] = TS_CURRENT for the server * parv[2] = TS_MIN for the server * parv[3] = server is standalone or connected to non-TS only * parv[4] = server's idea of UTC time */ void bahamut_cmd_svinfo() { send_cmd(NULL, "SVINFO 3 1 0 :%ld", static_cast(time(NULL))); } /* PASS */ void bahamut_cmd_pass(const char *pass) { send_cmd(NULL, "PASS %s :TS", pass); } /* CAPAB */ void bahamut_cmd_capab() { send_cmd(NULL, "CAPAB SSJOIN NOQUIT BURST UNCONNECT NICKIP TSMODE TS3"); } /* this avoids "undefined symbol" messages of those whom try to load mods that call on this function */ void bahamut_cmd_chghost(const char *nick, const char *vhost) { if (debug) { alog("debug: This IRCD does not support vhosting"); } } class BahamutIRCdProto : public IRCDProto { void ProcessUsermodes(User *user, int ac, const char **av) { int add = 1; /* 1 if adding modes, 0 if deleting */ const char *modes = av[0]; --ac; if (debug) alog("debug: Changing mode for %s to %s", user->nick, modes); while (*modes) { if (add) user->SetMode(*modes); else user->RemoveMode(*modes); switch (*modes++) { case '+': add = 1; break; case '-': add = 0; break; case 'd': if (!ac) { alog("user: umode +d with no parameter (?) for user %s", user->nick); break; } --ac; ++av; break; case 'o': if (add) { ++opcnt; if (Config.WallOper) ircdproto->SendGlobops(Config.s_OperServ, "\2%s\2 is now an IRC operator.", user->nick); } else --opcnt; break; case 'r': if (add && !nick_identified(user)) { common_svsmode(user, "-r", NULL); user->RemoveMode(CMODE_REGISTERED); } } } } void SendModeInternal(BotInfo *source, const char *dest, const char *buf) { if (!buf) return; if (ircdcap->tsmode && (uplink_capab & ircdcap->tsmode)) send_cmd(source->nick, "MODE %s 0 %s", dest, buf); else send_cmd(source->nick, "MODE %s %s", dest, buf); } /* SVSHOLD - set */ void SendSVSHold(const char *nick) { send_cmd(Config.ServerName, "SVSHOLD %s %u :%s", nick, static_cast(Config.NSReleaseTimeout), "Being held for registered user"); } /* SVSHOLD - release */ void SendSVSHoldDel(const char *nick) { send_cmd(Config.ServerName, "SVSHOLD %s 0", nick); } /* SVSMODE -b */ void SendBanDel(const char *name, const char *nick) { SendSVSModeChan(name, "-b", nick); } /* SVSMODE channel modes */ void SendSVSModeChan(const char *name, const char *mode, const char *nick) { if (nick) send_cmd(Config.ServerName, "SVSMODE %s %s %s", name, mode, nick); else send_cmd(Config.ServerName, "SVSMODE %s %s", name, mode); } void SendBotOp(const char *nick, const char *chan) { SendMode(findbot(nick), chan, "%s %s", ircd->botchanumode, nick); } /* SQLINE */ void SendSQLine(const char *mask, const char *reason) { if (!mask || !reason) return; send_cmd(NULL, "SQLINE %s :%s", mask, reason); } /* UNSGLINE */ void SendSGLineDel(const char *mask) { send_cmd(NULL, "UNSGLINE 0 :%s", mask); } /* UNSZLINE */ void SendSZLineDel(const char *mask) { /* this will likely fail so its only here for legacy */ send_cmd(NULL, "UNSZLINE 0 %s", mask); /* this is how we are supposed to deal with it */ send_cmd(NULL, "RAKILL %s *", mask); } /* SZLINE */ void SendSZLine(const char *mask, const char *reason, const char *whom) { /* this will likely fail so its only here for legacy */ send_cmd(NULL, "SZLINE %s :%s", mask, reason); /* this is how we are supposed to deal with it */ send_cmd(NULL, "AKILL %s * %d %s %ld :%s", mask, 172800, whom, static_cast(time(NULL)), reason); } /* SVSNOOP */ void SendSVSNOOP(const char *server, int set) { send_cmd(NULL, "SVSNOOP %s %s", server, set ? "+" : "-"); } /* SGLINE */ void SendSGLine(const char *mask, const char *reason) { send_cmd(NULL, "SGLINE %d :%s:%s", static_cast(strlen(mask)), mask, reason); } /* RAKILL */ void SendAkillDel(const char *user, const char *host) { send_cmd(NULL, "RAKILL %s %s", host, user); } /* TOPIC */ void SendTopic(BotInfo *whosets, const char *chan, const char *whosetit, const char *topic, time_t when) { send_cmd(whosets->nick, "TOPIC %s %s %lu :%s", chan, whosetit, static_cast(when), topic); } /* UNSQLINE */ void SendSQLineDel(const char *user) { send_cmd(NULL, "UNSQLINE %s", user); } /* JOIN - SJOIN */ void SendJoin(BotInfo *user, const char *channel, time_t chantime) { send_cmd(user->nick, "SJOIN %ld %s", static_cast(chantime), channel); } /* AKILL * parv[1]=host * parv[2]=user * parv[3]=length * parv[4]=akiller * parv[5]=time set * parv[6]=reason */ void SendAkill(const char *user, const char *host, const char *who, time_t when, time_t expires, const char *reason) { // Calculate the time left before this would expire, capping it at 2 days time_t timeleft = expires - time(NULL); if (timeleft > 172800) timeleft = 172800; send_cmd(NULL, "AKILL %s %s %d %s %ld :%s", host, user, static_cast(timeleft), who, static_cast(time(NULL)), reason); } /* SVSKILL */ /* parv[0] = servername * parv[1] = client * parv[2] = nick stamp * parv[3] = kill message */ /* Note: if the stamp is null 0, the below usage is correct of Bahamut */ void SendSVSKillInternal(const char *source, const char *user, const char *buf) { if (!source || !user || !buf) return; send_cmd(source, "SVSKILL %s :%s", user, buf); } /* SVSMODE */ /* parv[0] - sender * parv[1] - nick * parv[2] - TS (or mode, depending on svs version) * parv[3] - mode (or services id if old svs version) * parv[4] - optional arguement (services id) */ void SendSVSMode(User *u, int ac, const char **av) { send_cmd(Config.ServerName, "SVSMODE %s %ld %s", u->nick, static_cast(u->timestamp), merge_args(ac, av)); } void SendEOB() { send_cmd(NULL, "BURST 0"); } void SendNoticeChanopsInternal(BotInfo *source, const char *dest, const char *buf) { if (!buf) return; send_cmd(NULL, "NOTICE @%s :%s", dest, buf); } void SendKickInternal(BotInfo *source, const char *chan, const char *user, const char *buf) { if (buf) send_cmd(source->nick, "KICK %s %s :%s", chan, user, buf); else send_cmd(source->nick, "KICK %s %s", chan, user); } void SendClientIntroduction(const char *nick, const char *user, const char *host, const char *real, const char *modes, const char *uid) { EnforceQlinedNick(nick, Config.s_BotServ); send_cmd(NULL, "NICK %s 1 %ld %s %s %s %s 0 0 :%s", nick, static_cast(time(NULL)), modes, user, host, Config.ServerName, real); SendSQLine(nick, "Reserved for services"); } /* SVSMODE +d */ /* nc_change was = 1, and there is no na->status */ void SendUnregisteredNick(User *u) { common_svsmode(u, "+d", "1"); } /* SERVER */ void SendServer(Server *server) { send_cmd(NULL, "SERVER %s %d :%s", server->name, server->hops, server->desc); } void SendConnect() { bahamut_cmd_pass(uplink_server->password); bahamut_cmd_capab(); me_server = new_server(NULL, Config.ServerName, Config.ServerDesc, SERVER_ISME, NULL); SendServer(me_server); bahamut_cmd_svinfo(); bahamut_cmd_burst(); } void SetAutoIdentificationToken(User *u) { char svidbuf[15], *c; if (!u->nc) return; srand(time(NULL)); snprintf(svidbuf, sizeof(svidbuf), "%d", rand()); if (u->nc->GetExt("authenticationtoken", c)) { delete [] c; u->nc->Shrink("authenticationtoken"); } u->nc->Extend("authenticationtoken", sstrdup(svidbuf)); common_svsmode(u, "+rd", svidbuf); } } ircd_proto; /* EVENT: SJOIN */ int anope_event_sjoin(const char *source, int ac, const char **av) { do_sjoin(source, ac, av); return MOD_CONT; } /* ** NICK - new ** source = NULL ** parv[0] = nickname ** parv[1] = hopcount ** parv[2] = timestamp ** parv[3] = modes ** parv[4] = username ** parv[5] = hostname ** parv[6] = server ** parv[7] = servicestamp ** parv[8] = IP ** parv[9] = info ** NICK - change ** source = oldnick ** parv[0] = new nickname ** parv[1] = hopcount */ int anope_event_nick(const char *source, int ac, const char **av) { User *user; if (ac != 2) { user = do_nick(source, av[0], av[4], av[5], av[6], av[9], strtoul(av[2], NULL, 10), strtoul(av[8], NULL, 0), NULL, NULL); if (user) { /* Check to see if the user should be identified because their * services id matches the one in their nickcore */ user->CheckAuthenticationToken(av[7]); ircdproto->ProcessUsermodes(user, 1, &av[3]); } } else { do_nick(source, av[0], NULL, NULL, NULL, NULL, strtoul(av[1], NULL, 10), 0, NULL, NULL); } return MOD_CONT; } /* EVENT : CAPAB */ int anope_event_capab(const char *source, int ac, const char **av) { capab_parse(ac, av); return MOD_CONT; } /* EVENT : OS */ int anope_event_os(const char *source, int ac, const char **av) { if (ac < 1) return MOD_CONT; m_privmsg(source, Config.s_OperServ, av[0]); return MOD_CONT; } /* EVENT : NS */ int anope_event_ns(const char *source, int ac, const char **av) { if (ac < 1) return MOD_CONT; m_privmsg(source, Config.s_NickServ, av[0]); return MOD_CONT; } /* EVENT : MS */ int anope_event_ms(const char *source, int ac, const char **av) { if (ac < 1) return MOD_CONT; m_privmsg(source, Config.s_MemoServ, av[0]); return MOD_CONT; } /* EVENT : HS */ int anope_event_hs(const char *source, int ac, const char **av) { if (ac < 1) return MOD_CONT; m_privmsg(source, Config.s_HostServ, av[0]); return MOD_CONT; } /* EVENT : CS */ int anope_event_cs(const char *source, int ac, const char **av) { if (ac < 1) return MOD_CONT; m_privmsg(source, Config.s_ChanServ, av[0]); return MOD_CONT; } int anope_event_436(const char *source, int ac, const char **av) { if (ac < 1) return MOD_CONT; m_nickcoll(av[0]); return MOD_CONT; } /* EVENT : SERVER */ int anope_event_server(const char *source, int ac, const char **av) { if (!stricmp(av[1], "1")) { uplink = sstrdup(av[0]); } do_server(source, av[0], av[1], av[2], NULL); return MOD_CONT; } /* EVENT : PRIVMSG */ int anope_event_privmsg(const char *source, int ac, const char **av) { if (ac != 2) return MOD_CONT; m_privmsg(source, av[0], av[1]); return MOD_CONT; } int anope_event_part(const char *source, int ac, const char **av) { if (ac < 1 || ac > 2) return MOD_CONT; do_part(source, ac, av); return MOD_CONT; } int anope_event_whois(const char *source, int ac, const char **av) { if (source && ac >= 1) { m_whois(source, av[0]); } return MOD_CONT; } int anope_event_topic(const char *source, int ac, const char **av) { if (ac != 4) return MOD_CONT; do_topic(source, ac, av); return MOD_CONT; } int anope_event_squit(const char *source, int ac, const char **av) { if (ac != 2) return MOD_CONT; do_squit(source, ac, av); return MOD_CONT; } int anope_event_quit(const char *source, int ac, const char **av) { if (ac != 1) return MOD_CONT; do_quit(source, ac, av); return MOD_CONT; } /* EVENT: MODE */ int anope_event_mode(const char *source, int ac, const char **av) { if (ac < 2) return MOD_CONT; if (*av[0] == '#' || *av[0] == '&') { do_cmode(source, ac, av); } else { do_umode(source, ac, av); } return MOD_CONT; } /* EVENT: KILL */ int anope_event_kill(const char *source, int ac, const char **av) { if (ac != 2) return MOD_CONT; m_kill(av[0], av[1]); return MOD_CONT; } /* EVENT: KICK */ int anope_event_kick(const char *source, int ac, const char **av) { if (ac != 3) return MOD_CONT; do_kick(source, ac, av); return MOD_CONT; } /* EVENT: JOIN */ int anope_event_join(const char *source, int ac, const char **av) { if (ac != 1) return MOD_CONT; do_join(source, ac, av); return MOD_CONT; } /* EVENT: MOTD */ int anope_event_motd(const char *source, int ac, const char **av) { if (!source) { return MOD_CONT; } m_motd(source); return MOD_CONT; } int anope_event_away(const char *source, int ac, const char **av) { if (!source) { return MOD_CONT; } m_away(source, (ac ? av[0] : NULL)); return MOD_CONT; } int anope_event_ping(const char *source, int ac, const char **av) { if (ac < 1) return MOD_CONT; ircdproto->SendPong(ac > 1 ? av[1] : Config.ServerName, av[0]); return MOD_CONT; } int anope_event_error(const char *source, int ac, const char **av) { if (ac >= 1) { if (debug) { alog("debug: %s", av[0]); } } return MOD_CONT; } int anope_event_burst(const char *source, int ac, const char **av) { Server *s; s = findserver(servlist, source); if (!ac) { /* for future use - start burst */ } else { /* If we found a server with the given source, that one just * finished bursting. If there was no source, then our uplink * server finished bursting. -GD */ if (!s && serv_uplink) s = serv_uplink; finish_sync(s, 1); } return MOD_CONT; } bool ChannelModeFlood::IsValid(const char *value) { char *dp, *end; if (value && *value != ':' && strtoul((*value == '*' ? value + 1 : value), &dp, 10) > 0 && *dp == ':' && *(++dp) && strtoul(dp, &end, 10) > 0 && !*end) return true; return false; } void moduleAddIRCDMsgs() { Message *m; /* now add the commands */ m = createMessage("436", anope_event_436); addCoreMessage(IRCD,m); m = createMessage("AWAY", anope_event_away); addCoreMessage(IRCD,m); m = createMessage("JOIN", anope_event_join); addCoreMessage(IRCD,m); m = createMessage("KICK", anope_event_kick); addCoreMessage(IRCD,m); m = createMessage("KILL", anope_event_kill); addCoreMessage(IRCD,m); m = createMessage("MODE", anope_event_mode); addCoreMessage(IRCD,m); m = createMessage("MOTD", anope_event_motd); addCoreMessage(IRCD,m); m = createMessage("NICK", anope_event_nick); addCoreMessage(IRCD,m); m = createMessage("PART", anope_event_part); addCoreMessage(IRCD,m); m = createMessage("PING", anope_event_ping); addCoreMessage(IRCD,m); m = createMessage("PRIVMSG", anope_event_privmsg); addCoreMessage(IRCD,m); m = createMessage("QUIT", anope_event_quit); addCoreMessage(IRCD,m); m = createMessage("SERVER", anope_event_server); addCoreMessage(IRCD,m); m = createMessage("SQUIT", anope_event_squit); addCoreMessage(IRCD,m); m = createMessage("TOPIC", anope_event_topic); addCoreMessage(IRCD,m); m = createMessage("WHOIS", anope_event_whois); addCoreMessage(IRCD,m); m = createMessage("SVSMODE", anope_event_mode); addCoreMessage(IRCD,m); m = createMessage("CAPAB", anope_event_capab); addCoreMessage(IRCD,m); m = createMessage("CS", anope_event_cs); addCoreMessage(IRCD,m); m = createMessage("HS", anope_event_hs); addCoreMessage(IRCD,m); m = createMessage("MS", anope_event_ms); addCoreMessage(IRCD,m); m = createMessage("NS", anope_event_ns); addCoreMessage(IRCD,m); m = createMessage("OS", anope_event_os); addCoreMessage(IRCD,m); m = createMessage("SJOIN", anope_event_sjoin); addCoreMessage(IRCD,m); m = createMessage("ERROR", anope_event_error); addCoreMessage(IRCD,m); m = createMessage("BURST", anope_event_burst); addCoreMessage(IRCD,m); } void moduleAddModes() { /* Add user modes */ ModeManager::AddUserMode('A', new UserMode(UMODE_SERV_ADMIN)); ModeManager::AddUserMode('R', new UserMode(UMODE_REGPRIV)); ModeManager::AddUserMode('a', new UserMode(UMODE_ADMIN)); ModeManager::AddUserMode('i', new UserMode(UMODE_INVIS)); ModeManager::AddUserMode('o', new UserMode(UMODE_OPER)); ModeManager::AddUserMode('r', new UserMode(UMODE_REGISTERED)); ModeManager::AddUserMode('s', new UserMode(UMODE_SNOMASK)); ModeManager::AddUserMode('w', new UserMode(UMODE_WALLOPS)); /* b/e/I */ ModeManager::AddChannelMode('b', new ChannelModeBan()); /* v/h/o/a/q */ ModeManager::AddChannelMode('v', new ChannelModeStatus(CMODE_VOICE, CUS_VOICE, '+')); ModeManager::AddChannelMode('o', new ChannelModeStatus(CMODE_OP, CUS_OP, '@', true)); /* Add channel modes */ ModeManager::AddChannelMode('c', new ChannelMode(CMODE_BLOCKCOLOR)); ModeManager::AddChannelMode('i', new ChannelMode(CMODE_INVITE)); ModeManager::AddChannelMode('j', new ChannelModeFlood()); ModeManager::AddChannelMode('k', new ChannelModeKey()); ModeManager::AddChannelMode('l', new ChannelModeParam(CMODE_LIMIT)); ModeManager::AddChannelMode('m', new ChannelMode(CMODE_MODERATED)); ModeManager::AddChannelMode('n', new ChannelMode(CMODE_NOEXTERNAL)); ModeManager::AddChannelMode('p', new ChannelMode(CMODE_PRIVATE)); ModeManager::AddChannelMode('r', new ChannelModeRegistered()); ModeManager::AddChannelMode('s', new ChannelMode(CMODE_SECRET)); ModeManager::AddChannelMode('t', new ChannelMode(CMODE_TOPIC)); ModeManager::AddChannelMode('M', new ChannelMode(CMODE_REGMODERATED)); ModeManager::AddChannelMode('O', new ChannelModeOper()); ModeManager::AddChannelMode('R', new ChannelMode(CMODE_REGISTEREDONLY)); } class ProtoBahamut : public Module { public: ProtoBahamut(const std::string &modname, const std::string &creator) : Module(modname, creator) { this->SetAuthor("Anope"); this->SetVersion("$Id$"); this->SetType(PROTOCOL); pmodule_ircd_version("BahamutIRCd 1.4.*/1.8.*"); pmodule_ircd_cap(myIrcdcap); pmodule_ircd_var(myIrcd); pmodule_ircd_useTSMode(0); moduleAddModes(); ircd->DefMLock[CMODE_NOEXTERNAL] = true; ircd->DefMLock[CMODE_TOPIC] = true; ircd->DefMLock[CMODE_REGISTERED] = true; pmodule_ircd_proto(&ircd_proto); moduleAddIRCDMsgs(); ModuleManager::Attach(I_OnDelCore, this); } void OnDelCore(NickCore *nc) { char *c; if (nc->GetExt("authenticationtoken", c)) { delete [] c; nc->Shrink("authenticationtoken"); } } }; MODULE_INIT(ProtoBahamut)