anope

- supernets anope source code & configuration
git clone git://git.acid.vegas/anope.git
Log | Files | Refs | Archive | README

charybdis.cpp (16368B)

      1 /* Charybdis IRCD functions
      2  *
      3  * (C) 2003-2022 Anope Team
      4  * Contact us at team@anope.org
      5  *
      6  * Please read COPYING and README for further details.
      7  *
      8  * Based on the original code of Epona by Lara.
      9  * Based on the original code of Services by Andy Church.
     10  */
     11 
     12 #include "module.h"
     13 #include "modules/cs_mode.h"
     14 #include "modules/sasl.h"
     15 
     16 static Anope::string UplinkSID;
     17 
     18 static ServiceReference<IRCDProto> ratbox("IRCDProto", "ratbox");
     19 
     20 class ChannelModeLargeBan : public ChannelMode
     21 {
     22  public:
     23 	ChannelModeLargeBan(const Anope::string &mname, char modeChar) : ChannelMode(mname, modeChar) { }
     24 
     25 	bool CanSet(User *u) const anope_override
     26 	{
     27 		return u && u->HasMode("OPER");
     28 	}
     29 };
     30 
     31 
     32 class CharybdisProto : public IRCDProto
     33 {
     34  public:
     35 
     36 	CharybdisProto(Module *creator) : IRCDProto(creator, "Charybdis 3.4+")
     37 	{
     38 		DefaultPseudoclientModes = "+oiS";
     39 		CanCertFP = true;
     40 		CanSNLine = true;
     41 		CanSQLine = true;
     42 		CanSQLineChannel = true;
     43 		CanSZLine = true;
     44 		CanSVSNick = true;
     45 		CanSVSHold = true;
     46 		CanSetVHost = true;
     47 		RequiresID = true;
     48 		MaxModes = 4;
     49 	}
     50 
     51 	void SendSVSKillInternal(const MessageSource &source, User *targ, const Anope::string &reason) anope_override { ratbox->SendSVSKillInternal(source, targ, reason); }
     52 	void SendGlobalNotice(BotInfo *bi, const Server *dest, const Anope::string &msg) anope_override { ratbox->SendGlobalNotice(bi, dest, msg); }
     53 	void SendGlobalPrivmsg(BotInfo *bi, const Server *dest, const Anope::string &msg) anope_override { ratbox->SendGlobalPrivmsg(bi, dest, msg); }
     54 	void SendGlobopsInternal(const MessageSource &source, const Anope::string &buf) anope_override { ratbox->SendGlobopsInternal(source, buf); }
     55 	void SendSGLine(User *u, const XLine *x) anope_override { ratbox->SendSGLine(u, x); }
     56 	void SendSGLineDel(const XLine *x) anope_override { ratbox->SendSGLineDel(x); }
     57 	void SendAkill(User *u, XLine *x) anope_override { ratbox->SendAkill(u, x); }
     58 	void SendAkillDel(const XLine *x) anope_override { ratbox->SendAkillDel(x); }
     59 	void SendSQLine(User *u, const XLine *x) anope_override { ratbox->SendSQLine(u, x); }
     60 	void SendSQLineDel(const XLine *x) anope_override { ratbox->SendSQLineDel(x); }
     61 	void SendJoin(User *user, Channel *c, const ChannelStatus *status) anope_override { ratbox->SendJoin(user, c, status); }
     62 	void SendServer(const Server *server) anope_override { ratbox->SendServer(server); }
     63 	void SendChannel(Channel *c) anope_override { ratbox->SendChannel(c); }
     64 	void SendTopic(const MessageSource &source, Channel *c) anope_override { ratbox->SendTopic(source, c); }
     65 	bool IsIdentValid(const Anope::string &ident) anope_override { return ratbox->IsIdentValid(ident); }
     66 	void SendLogin(User *u, NickAlias *na) anope_override { ratbox->SendLogin(u, na); }
     67 	void SendLogout(User *u) anope_override { ratbox->SendLogout(u); }
     68 
     69 	void SendSASLMechanisms(std::vector<Anope::string> &mechanisms) anope_override
     70 	{
     71 		Anope::string mechlist;
     72 
     73 		for (unsigned i = 0; i < mechanisms.size(); ++i)
     74 		{
     75 			mechlist += "," + mechanisms[i];
     76 		}
     77 
     78 		UplinkSocket::Message(Me) << "ENCAP * MECHLIST :" << (mechanisms.empty() ? "" : mechlist.substr(1));
     79 	}
     80 
     81 	void SendConnect() anope_override
     82 	{
     83 		UplinkSocket::Message() << "PASS " << Config->Uplinks[Anope::CurrentUplink].password << " TS 6 :" << Me->GetSID();
     84 		/*
     85 		 * Received: CAPAB :BAN CHW CLUSTER ENCAP EOPMOD EUID EX IE KLN
     86 		 *           KNOCK MLOCK QS RSFNC SAVE SERVICES TB UNKLN
     87 		 *
     88 		 * BAN      - Can do BAN message
     89 		 * CHW      - Can do channel wall @#
     90 		 * CLUSTER  - Supports umode +l, can send LOCOPS (encap only)
     91 		 * ENCAP    - Can do ENCAP message
     92 		 * EOPMOD   - Can do channel wall =# (for cmode +z)
     93 		 * EUID     - Can do EUID (its similar to UID but includes the ENCAP REALHOST and ENCAP LOGIN information)
     94 		 * EX       - Can do channel +e exemptions
     95 		 * GLN      - Can set G:Lines
     96 		 * IE       - Can do invite exceptions
     97 		 * KLN      - Can set K:Lines (encap only)
     98 		 * KNOCK    - Supports KNOCK
     99 		 * MLOCK    - Supports MLOCK
    100 		 * RSFNC    - Forces a nickname change and propagates it (encap only)
    101 		 * SERVICES - Support channel mode +r (only registered users may join)
    102 		 * SAVE     - Resolve a nick collision by changing a nickname to the UID.
    103 		 * TB       - Supports topic burst
    104 		 * UNKLN    - Can do UNKLINE (encap only)
    105 		 * QS       - Can handle quit storm removal
    106 		*/
    107 		UplinkSocket::Message() << "CAPAB :BAN CHW CLUSTER ENCAP EOPMOD EUID EX IE KLN KNOCK MLOCK QS RSFNC SERVICES TB UNKLN";
    108 
    109 		/* Make myself known to myself in the serverlist */
    110 		SendServer(Me);
    111 
    112 		/*
    113 		 * Received: SVINFO 6 6 0 :1353235537
    114 		 *  arg[0] = current TS version
    115 		 *  arg[1] = minimum required TS version
    116 		 *  arg[2] = '0'
    117 		 *  arg[3] = server's idea of UTC time
    118 		 */
    119 		UplinkSocket::Message() << "SVINFO 6 6 0 :" << Anope::CurTime;
    120 	}
    121 
    122 	void SendClientIntroduction(User *u) anope_override
    123 	{
    124 		Anope::string modes = "+" + u->GetModes();
    125 		UplinkSocket::Message(Me) << "EUID " << u->nick << " 1 " << u->timestamp << " " << modes << " " << u->GetIdent() << " " << u->host << " 0 " << u->GetUID() << " * * :" << u->realname;
    126 	}
    127 
    128 	void SendForceNickChange(User *u, const Anope::string &newnick, time_t when) anope_override
    129 	{
    130 		UplinkSocket::Message(Me) << "ENCAP " << u->server->GetName() << " RSFNC " << u->GetUID()
    131 						<< " " << newnick << " " << when << " " << u->timestamp;
    132 	}
    133 
    134 	void SendSVSHold(const Anope::string &nick, time_t delay) anope_override
    135 	{
    136 		UplinkSocket::Message(Me) << "ENCAP * NICKDELAY " << delay << " " << nick;
    137 	}
    138 
    139 	void SendSVSHoldDel(const Anope::string &nick) anope_override
    140 	{
    141 		UplinkSocket::Message(Me) << "ENCAP * NICKDELAY 0 " << nick;
    142 	}
    143 
    144 	void SendVhost(User *u, const Anope::string &ident, const Anope::string &host) anope_override
    145 	{
    146 		UplinkSocket::Message(Me) << "ENCAP * CHGHOST " << u->GetUID() << " :" << host;
    147 	}
    148 
    149 	void SendVhostDel(User *u) anope_override
    150 	{
    151 		this->SendVhost(u, "", u->host);
    152 	}
    153 
    154 	void SendSASLMessage(const SASL::Message &message) anope_override
    155 	{
    156 		Server *s = Server::Find(message.target.substr(0, 3));
    157 		UplinkSocket::Message(Me) << "ENCAP " << (s ? s->GetName() : message.target.substr(0, 3)) << " SASL " << message.source << " " << message.target << " " << message.type << " " << message.data << (message.ext.empty() ? "" : (" " + message.ext));
    158 	}
    159 
    160 	void SendSVSLogin(const Anope::string &uid, const Anope::string &acc, const Anope::string &vident, const Anope::string &vhost) anope_override
    161 	{
    162 		Server *s = Server::Find(uid.substr(0, 3));
    163 		UplinkSocket::Message(Me) << "ENCAP " << (s ? s->GetName() : uid.substr(0, 3)) << " SVSLOGIN " << uid << " * " << (!vident.empty() ? vident : '*') << " " << (!vhost.empty() ? vhost : '*') << " " << acc;
    164 	}
    165 };
    166 
    167 
    168 struct IRCDMessageEncap : IRCDMessage
    169 {
    170 	IRCDMessageEncap(Module *creator) : IRCDMessage(creator, "ENCAP", 3)
    171 	{
    172 		SetFlag(IRCDMESSAGE_SOFT_LIMIT);
    173 	}
    174 
    175 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
    176 	{
    177 		// In a burst, states that the source user is logged in as the account.
    178 		if (params[1] == "LOGIN" || params[1] == "SU")
    179 		{
    180 			User *u = source.GetUser();
    181 			NickCore *nc = NickCore::Find(params[2]);
    182 
    183 			if (!u || !nc)
    184 				return;
    185 
    186 			u->Login(nc);
    187 		}
    188 		// Received: :42XAAAAAE ENCAP * CERTFP :3f122a9cc7811dbad3566bf2cec3009007c0868f
    189 		else if (params[1] == "CERTFP")
    190 		{
    191 			User *u = source.GetUser();
    192 			if (!u)
    193 				return;
    194 
    195 			u->fingerprint = params[2];
    196 
    197 			FOREACH_MOD(OnFingerprint, (u));
    198 		}
    199 		/*
    200 		 * Received: :42X ENCAP * SASL 42XAAAAAH * S PLAIN
    201 		 * Received: :42X ENCAP * SASL 42XAAAAAC * D A
    202 		 *
    203 		 * Part of a SASL authentication exchange. The mode is 'C' to send some data
    204 		 * (base64 encoded), or 'S' to end the exchange (data indicates type of
    205 		 * termination: 'A' for abort, 'F' for authentication failure, 'S' for
    206 		 * authentication success).
    207 		 *
    208 		 * Charybdis only accepts messages from SASL agents; these must have umode +S
    209 		 */
    210 		else if (params[1] == "SASL" && SASL::sasl && params.size() >= 6)
    211 		{
    212 			SASL::Message m;
    213 			m.source = params[2];
    214 			m.target = params[3];
    215 			m.type = params[4];
    216 			m.data = params[5];
    217 			m.ext = params.size() > 6 ? params[6] : "";
    218 
    219 			SASL::sasl->ProcessMessage(m);
    220 		}
    221 	}
    222 };
    223 
    224 struct IRCDMessageEUID : IRCDMessage
    225 {
    226 	IRCDMessageEUID(Module *creator) : IRCDMessage(creator, "EUID", 11) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); }
    227 
    228 	/*
    229 	 * :42X EUID DukePyrolator 1 1353240577 +Zi ~jens erft-5d80b00b.pool.mediaWays.net 93.128.176.11 42XAAAAAD * * :jens
    230 	 * :<SID> EUID <NICK> <HOPS> <TS> +<UMODE> <USERNAME> <VHOST> <IP> <UID> <REALHOST> <ACCOUNT> :<GECOS>
    231 	 *               0      1     2      3         4         5     6     7       8         9         10
    232 	 *
    233 	 * Introduces a user. The hostname field is now always the visible host.
    234 	 * The realhost field is * if the real host is equal to the visible host.
    235 	 * The account field is * if the login is not set.
    236 	 * Note that even if both new fields are *, an EUID command still carries more
    237 	 * information than a UID command (namely that real host is visible host and the
    238 	 * user is not logged in with services). Hence a NICK or UID command received
    239 	 * from a remote server should not be sent in EUID form to other servers.
    240 	 */
    241 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
    242 	{
    243 		NickAlias *na = NULL;
    244 		if (params[9] != "*")
    245 			na = NickAlias::Find(params[9]);
    246 
    247 		User::OnIntroduce(params[0], params[4], (params[8] != "*" ? params[8] : params[5]), params[5], params[6], source.GetServer(), params[10], params[2].is_pos_number_only() ? convertTo<time_t>(params[2]) : Anope::CurTime, params[3], params[7], na ? *na->nc : NULL);
    248 	}
    249 };
    250 
    251 // we can't use this function from ratbox because we set a local variable here
    252 struct IRCDMessageServer : IRCDMessage
    253 {
    254 	IRCDMessageServer(Module *creator) : IRCDMessage(creator, "SERVER", 3) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); }
    255 
    256 	// SERVER dev.anope.de 1 :charybdis test server
    257 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
    258 	{
    259 		// Servers other then our immediate uplink are introduced via SID
    260 		if (params[1] != "1")
    261 			return;
    262 		new Server(source.GetServer() == NULL ? Me : source.GetServer(), params[0], 1, params[2], UplinkSID);
    263 		IRCD->SendPing(Me->GetName(), params[0]);
    264 	}
    265 };
    266 
    267 // we can't use this function from ratbox because we set a local variable here
    268 struct IRCDMessagePass : IRCDMessage
    269 {
    270 	IRCDMessagePass(Module *creator) : IRCDMessage(creator, "PASS", 4) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); }
    271 
    272 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
    273 	{
    274 		// UplinkSID is used in IRCDMessageServer
    275 		UplinkSID = params[3];
    276 	}
    277 };
    278 
    279 class ProtoCharybdis : public Module
    280 {
    281 	Module *m_ratbox;
    282 
    283 	CharybdisProto ircd_proto;
    284 
    285 	/* Core message handlers */
    286 	Message::Away message_away;
    287 	Message::Capab message_capab;
    288 	Message::Error message_error;
    289 	Message::Invite message_invite;
    290 	Message::Kick message_kick;
    291 	Message::Kill message_kill;
    292 	Message::Mode message_mode;
    293 	Message::MOTD message_motd;
    294 	Message::Notice message_notice;
    295 	Message::Part message_part;
    296 	Message::Ping message_ping;
    297 	Message::Privmsg message_privmsg;
    298 	Message::Quit message_quit;
    299 	Message::SQuit message_squit;
    300 	Message::Stats message_stats;
    301 	Message::Time message_time;
    302 	Message::Topic message_topic;
    303 	Message::Version message_version;
    304 	Message::Whois message_whois;
    305 
    306 	/* Ratbox Message Handlers */
    307 	ServiceAlias message_bmask, message_join, message_nick, message_pong, message_sid, message_sjoin,
    308 		message_tb, message_tmode, message_uid;
    309 
    310 	/* Our message handlers */
    311 	IRCDMessageEncap message_encap;
    312 	IRCDMessageEUID message_euid;
    313 	IRCDMessagePass message_pass;
    314 	IRCDMessageServer message_server;
    315 
    316 	bool use_server_side_mlock;
    317 
    318 	void AddModes()
    319 	{
    320 		/* Add user modes */
    321 		ModeManager::AddUserMode(new UserMode("NOFORWARD", 'Q'));
    322 		ModeManager::AddUserMode(new UserMode("REGPRIV", 'R'));
    323 		ModeManager::AddUserMode(new UserModeOperOnly("OPERWALLS", 'z'));
    324 		ModeManager::AddUserMode(new UserModeNoone("SSL", 'Z'));
    325 
    326 		/* b/e/I */
    327 		ModeManager::AddChannelMode(new ChannelModeList("QUIET", 'q'));
    328 
    329 		/* Add channel modes */
    330 		ModeManager::AddChannelMode(new ChannelMode("BLOCKCOLOR", 'c'));
    331 		ModeManager::AddChannelMode(new ChannelMode("NOCTCP", 'C'));
    332 		ModeManager::AddChannelMode(new ChannelModeParam("REDIRECT", 'f'));
    333 		ModeManager::AddChannelMode(new ChannelMode("ALLOWFORWARD", 'F'));
    334 		ModeManager::AddChannelMode(new ChannelMode("ALLINVITE", 'g'));
    335 		ModeManager::AddChannelMode(new ChannelModeParam("JOINFLOOD", 'j'));
    336 		ModeManager::AddChannelMode(new ChannelModeLargeBan("LBAN", 'L'));
    337 		ModeManager::AddChannelMode(new ChannelMode("PERM", 'P'));
    338 		ModeManager::AddChannelMode(new ChannelMode("NOFORWARD", 'Q'));
    339 		ModeManager::AddChannelMode(new ChannelMode("OPMODERATED", 'z'));
    340 	}
    341 
    342  public:
    343 	ProtoCharybdis(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, PROTOCOL | VENDOR),
    344 		ircd_proto(this),
    345 		message_away(this), message_capab(this), message_error(this), message_invite(this), message_kick(this),
    346 		message_kill(this), message_mode(this), message_motd(this), message_notice(this), message_part(this),
    347 		message_ping(this), message_privmsg(this), message_quit(this), message_squit(this), message_stats(this),
    348 		message_time(this), message_topic(this), message_version(this), message_whois(this),
    349 
    350 		message_bmask("IRCDMessage", "charybdis/bmask", "ratbox/bmask"),
    351 		message_join("IRCDMessage", "charybdis/join", "ratbox/join"),
    352 		message_nick("IRCDMessage", "charybdis/nick", "ratbox/nick"),
    353 		message_pong("IRCDMessage", "charybdis/pong", "ratbox/pong"),
    354 		message_sid("IRCDMessage", "charybdis/sid", "ratbox/sid"),
    355 		message_sjoin("IRCDMessage", "charybdis/sjoin", "ratbox/sjoin"),
    356 		message_tb("IRCDMessage", "charybdis/tb", "ratbox/tb"),
    357 		message_tmode("IRCDMessage", "charybdis/tmode", "ratbox/tmode"),
    358 		message_uid("IRCDMessage", "charybdis/uid", "ratbox/uid"),
    359 
    360 		message_encap(this), message_euid(this), message_pass(this), message_server(this)
    361 
    362 	{
    363 
    364 
    365 		if (ModuleManager::LoadModule("ratbox", User::Find(creator)) != MOD_ERR_OK)
    366 			throw ModuleException("Unable to load ratbox");
    367 		m_ratbox = ModuleManager::FindModule("ratbox");
    368 		if (!m_ratbox)
    369 			throw ModuleException("Unable to find ratbox");
    370 		if (!ratbox)
    371 			throw ModuleException("No protocol interface for ratbox");
    372 
    373 		this->AddModes();
    374 	}
    375 
    376 	~ProtoCharybdis()
    377 	{
    378 		m_ratbox = ModuleManager::FindModule("ratbox");
    379 		ModuleManager::UnloadModule(m_ratbox, NULL);
    380 	}
    381 
    382 	void OnReload(Configuration::Conf *conf) anope_override
    383 	{
    384 		use_server_side_mlock = conf->GetModule(this)->Get<bool>("use_server_side_mlock");
    385 	}
    386 
    387 	void OnChannelSync(Channel *c) anope_override
    388 	{
    389 		if (!c->ci)
    390 			return;
    391 
    392 		ModeLocks *modelocks = c->ci->GetExt<ModeLocks>("modelocks");
    393 		if (use_server_side_mlock && modelocks && Servers::Capab.count("MLOCK") > 0)
    394 		{
    395 			Anope::string modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", "");
    396 			UplinkSocket::Message(Me) << "MLOCK " << static_cast<long>(c->creation_time) << " " << c->ci->name << " " << modes;
    397 		}
    398 	}
    399 
    400 	EventReturn OnMLock(ChannelInfo *ci, ModeLock *lock) anope_override
    401 	{
    402 		ModeLocks *modelocks = ci->GetExt<ModeLocks>("modelocks");
    403 		ChannelMode *cm = ModeManager::FindChannelModeByName(lock->name);
    404 		if (use_server_side_mlock && cm && ci->c && modelocks && (cm->type == MODE_REGULAR || cm->type == MODE_PARAM) && Servers::Capab.count("MLOCK") > 0)
    405 		{
    406 			Anope::string modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", "") + cm->mchar;
    407 			UplinkSocket::Message(Me) << "MLOCK " << static_cast<long>(ci->c->creation_time) << " " << ci->name << " " << modes;
    408 		}
    409 
    410 		return EVENT_CONTINUE;
    411 	}
    412 
    413 	EventReturn OnUnMLock(ChannelInfo *ci, ModeLock *lock) anope_override
    414 	{
    415 		ModeLocks *modelocks = ci->GetExt<ModeLocks>("modelocks");
    416 		ChannelMode *cm = ModeManager::FindChannelModeByName(lock->name);
    417 		if (use_server_side_mlock && cm && modelocks && ci->c && (cm->type == MODE_REGULAR || cm->type == MODE_PARAM) && Servers::Capab.count("MLOCK") > 0)
    418 		{
    419 			Anope::string modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", "").replace_all_cs(cm->mchar, "");
    420 			UplinkSocket::Message(Me) << "MLOCK " << static_cast<long>(ci->c->creation_time) << " " << ci->name << " " << modes;
    421 		}
    422 
    423 		return EVENT_CONTINUE;
    424 	}
    425 };
    426 
    427 MODULE_INIT(ProtoCharybdis)