1 /*
2 *
3 * (C) 2003-2020 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 "services.h"
13 #include "modules.h"
14 #include "protocol.h"
15 #include "users.h"
16 #include "servers.h"
17 #include "config.h"
18 #include "uplink.h"
19 #include "bots.h"
20 #include "channels.h"
21
22 IRCDProto *IRCD = NULL;
23
IRCDProto(Module * creator,const Anope::string & p)24 IRCDProto::IRCDProto(Module *creator, const Anope::string &p) : Service(creator, "IRCDProto", creator->name), proto_name(p)
25 {
26 DefaultPseudoclientModes = "+io";
27 CanSVSNick = CanSVSJoin = CanSetVHost = CanSetVIdent = CanSNLine = CanSQLine = CanSQLineChannel
28 = CanSZLine = CanSVSHold = CanSVSO = CanCertFP = RequiresID = AmbiguousID = false;
29 MaxModes = 3;
30 MaxLine = 512;
31
32 if (IRCD == NULL)
33 IRCD = this;
34 }
35
~IRCDProto()36 IRCDProto::~IRCDProto()
37 {
38 if (IRCD == this)
39 IRCD = NULL;
40 }
41
GetProtocolName()42 const Anope::string &IRCDProto::GetProtocolName()
43 {
44 return this->proto_name;
45 }
46
nextID(int pos,Anope::string & buf)47 static inline char nextID(int pos, Anope::string &buf)
48 {
49 char &c = buf[pos];
50 if (c == 'Z')
51 c = '0';
52 else if (c != '9')
53 ++c;
54 else if (pos)
55 c = 'A';
56 else
57 c = '0';
58 return c;
59 }
60
UID_Retrieve()61 Anope::string IRCDProto::UID_Retrieve()
62 {
63 if (!IRCD || !IRCD->RequiresID)
64 return "";
65
66 static Anope::string current_uid = "AAAAAA";
67
68 do
69 {
70 int current_len = current_uid.length() - 1;
71 while (current_len >= 0 && nextID(current_len--, current_uid) == 'A');
72 }
73 while (User::Find(Me->GetSID() + current_uid) != NULL);
74
75 return Me->GetSID() + current_uid;
76 }
77
SID_Retrieve()78 Anope::string IRCDProto::SID_Retrieve()
79 {
80 if (!IRCD || !IRCD->RequiresID)
81 return "";
82
83 static Anope::string current_sid = Config->GetBlock("serverinfo")->Get<const Anope::string>("id");
84 if (current_sid.empty())
85 current_sid = "00A";
86
87 do
88 {
89 int current_len = current_sid.length() - 1;
90 while (current_len >= 0 && nextID(current_len--, current_sid) == 'A');
91 }
92 while (Server::Find(current_sid) != NULL);
93
94 return current_sid;
95 }
96
SendKill(const MessageSource & source,const Anope::string & target,const Anope::string & reason)97 void IRCDProto::SendKill(const MessageSource &source, const Anope::string &target, const Anope::string &reason)
98 {
99 UplinkSocket::Message(source) << "KILL " << target << " :" << reason;
100 }
101
SendSVSKillInternal(const MessageSource & source,User * user,const Anope::string & buf)102 void IRCDProto::SendSVSKillInternal(const MessageSource &source, User *user, const Anope::string &buf)
103 {
104 UplinkSocket::Message(source) << "KILL " << user->GetUID() << " :" << buf;
105 }
106
SendModeInternal(const MessageSource & source,const Channel * dest,const Anope::string & buf)107 void IRCDProto::SendModeInternal(const MessageSource &source, const Channel *dest, const Anope::string &buf)
108 {
109 UplinkSocket::Message(source) << "MODE " << dest->name << " " << buf;
110 }
111
SendModeInternal(const MessageSource & source,User * dest,const Anope::string & buf)112 void IRCDProto::SendModeInternal(const MessageSource &source, User *dest, const Anope::string &buf)
113 {
114 UplinkSocket::Message(source) << "MODE " << dest->GetUID() << " " << buf;
115 }
116
SendKickInternal(const MessageSource & source,const Channel * c,User * u,const Anope::string & r)117 void IRCDProto::SendKickInternal(const MessageSource &source, const Channel *c, User *u, const Anope::string &r)
118 {
119 if (!r.empty())
120 UplinkSocket::Message(source) << "KICK " << c->name << " " << u->GetUID() << " :" << r;
121 else
122 UplinkSocket::Message(source) << "KICK " << c->name << " " << u->GetUID();
123 }
124
SendNoticeInternal(const MessageSource & source,const Anope::string & dest,const Anope::string & msg)125 void IRCDProto::SendNoticeInternal(const MessageSource &source, const Anope::string &dest, const Anope::string &msg)
126 {
127 UplinkSocket::Message(source) << "NOTICE " << dest << " :" << msg;
128 }
129
SendPrivmsgInternal(const MessageSource & source,const Anope::string & dest,const Anope::string & buf)130 void IRCDProto::SendPrivmsgInternal(const MessageSource &source, const Anope::string &dest, const Anope::string &buf)
131 {
132 UplinkSocket::Message(source) << "PRIVMSG " << dest << " :" << buf;
133 }
134
SendQuitInternal(User * u,const Anope::string & buf)135 void IRCDProto::SendQuitInternal(User *u, const Anope::string &buf)
136 {
137 if (!buf.empty())
138 UplinkSocket::Message(u) << "QUIT :" << buf;
139 else
140 UplinkSocket::Message(u) << "QUIT";
141 }
142
SendPartInternal(User * u,const Channel * chan,const Anope::string & buf)143 void IRCDProto::SendPartInternal(User *u, const Channel *chan, const Anope::string &buf)
144 {
145 if (!buf.empty())
146 UplinkSocket::Message(u) << "PART " << chan->name << " :" << buf;
147 else
148 UplinkSocket::Message(u) << "PART " << chan->name;
149 }
150
SendGlobopsInternal(const MessageSource & source,const Anope::string & buf)151 void IRCDProto::SendGlobopsInternal(const MessageSource &source, const Anope::string &buf)
152 {
153 UplinkSocket::Message(source) << "GLOBOPS :" << buf;
154 }
155
SendCTCPInternal(const MessageSource & source,const Anope::string & dest,const Anope::string & buf)156 void IRCDProto::SendCTCPInternal(const MessageSource &source, const Anope::string &dest, const Anope::string &buf)
157 {
158 Anope::string s = Anope::NormalizeBuffer(buf);
159 this->SendNoticeInternal(source, dest, "\1" + s + "\1");
160 }
161
SendNumericInternal(int numeric,const Anope::string & dest,const Anope::string & buf)162 void IRCDProto::SendNumericInternal(int numeric, const Anope::string &dest, const Anope::string &buf)
163 {
164 Anope::string n = stringify(numeric);
165 if (numeric < 10)
166 n = "0" + n;
167 if (numeric < 100)
168 n = "0" + n;
169 UplinkSocket::Message(Me) << n << " " << dest << " " << buf;
170 }
171
SendTopic(const MessageSource & source,Channel * c)172 void IRCDProto::SendTopic(const MessageSource &source, Channel *c)
173 {
174 UplinkSocket::Message(source) << "TOPIC " << c->name << " :" << c->topic;
175 }
176
SendSVSKill(const MessageSource & source,User * user,const char * fmt,...)177 void IRCDProto::SendSVSKill(const MessageSource &source, User *user, const char *fmt, ...)
178 {
179 if (!user || !fmt)
180 return;
181
182 va_list args;
183 char buf[BUFSIZE] = "";
184 va_start(args, fmt);
185 vsnprintf(buf, BUFSIZE - 1, fmt, args);
186 va_end(args);
187 SendSVSKillInternal(source, user, buf);
188 }
189
SendMode(const MessageSource & source,const Channel * dest,const char * fmt,...)190 void IRCDProto::SendMode(const MessageSource &source, const Channel *dest, const char *fmt, ...)
191 {
192 va_list args;
193 char buf[BUFSIZE] = "";
194 va_start(args, fmt);
195 vsnprintf(buf, BUFSIZE - 1, fmt, args);
196 va_end(args);
197 SendModeInternal(source, dest, buf);
198 }
199
SendMode(const MessageSource & source,User * u,const char * fmt,...)200 void IRCDProto::SendMode(const MessageSource &source, User *u, const char *fmt, ...)
201 {
202 va_list args;
203 char buf[BUFSIZE] = "";
204 va_start(args, fmt);
205 vsnprintf(buf, BUFSIZE - 1, fmt, args);
206 va_end(args);
207 SendModeInternal(source, u, buf);
208 }
209
SendKick(const MessageSource & source,const Channel * chan,User * user,const char * fmt,...)210 void IRCDProto::SendKick(const MessageSource &source, const Channel *chan, User *user, const char *fmt, ...)
211 {
212 if (!chan || !user)
213 return;
214
215 va_list args;
216 char buf[BUFSIZE] = "";
217 va_start(args, fmt);
218 vsnprintf(buf, BUFSIZE - 1, fmt, args);
219 va_end(args);
220 SendKickInternal(source, chan, user, buf);
221 }
222
SendNotice(const MessageSource & source,const Anope::string & dest,const char * fmt,...)223 void IRCDProto::SendNotice(const MessageSource &source, const Anope::string &dest, const char *fmt, ...)
224 {
225 va_list args;
226 char buf[BUFSIZE] = "";
227 va_start(args, fmt);
228 vsnprintf(buf, BUFSIZE - 1, fmt, args);
229 va_end(args);
230 SendNoticeInternal(source, dest, buf);
231 }
232
SendAction(const MessageSource & source,const Anope::string & dest,const char * fmt,...)233 void IRCDProto::SendAction(const MessageSource &source, const Anope::string &dest, const char *fmt, ...)
234 {
235 va_list args;
236 char buf[BUFSIZE] = "";
237 va_start(args, fmt);
238 vsnprintf(buf, BUFSIZE - 1, fmt, args);
239 va_end(args);
240 Anope::string actionbuf = Anope::string("\1ACTION ") + buf + '\1';
241 SendPrivmsgInternal(source, dest, actionbuf);
242 }
243
SendPrivmsg(const MessageSource & source,const Anope::string & dest,const char * fmt,...)244 void IRCDProto::SendPrivmsg(const MessageSource &source, const Anope::string &dest, const char *fmt, ...)
245 {
246 va_list args;
247 char buf[BUFSIZE] = "";
248 va_start(args, fmt);
249 vsnprintf(buf, BUFSIZE - 1, fmt, args);
250 va_end(args);
251 SendPrivmsgInternal(source, dest, buf);
252 }
253
SendQuit(User * u,const char * fmt,...)254 void IRCDProto::SendQuit(User *u, const char *fmt, ...)
255 {
256 va_list args;
257 char buf[BUFSIZE] = "";
258 va_start(args, fmt);
259 vsnprintf(buf, BUFSIZE - 1, fmt, args);
260 va_end(args);
261 SendQuitInternal(u, buf);
262 }
263
SendPing(const Anope::string & servname,const Anope::string & who)264 void IRCDProto::SendPing(const Anope::string &servname, const Anope::string &who)
265 {
266 if (servname.empty())
267 UplinkSocket::Message(Me) << "PING " << who;
268 else
269 UplinkSocket::Message(Me) << "PING " << servname << " " << who;
270 }
271
272 /**
273 * Send a PONG reply to a received PING.
274 * servname should be left NULL to send a one param reply.
275 * @param servname Daemon or client that is responding to the PING.
276 * @param who Origin of the PING and destination of the PONG message.
277 **/
SendPong(const Anope::string & servname,const Anope::string & who)278 void IRCDProto::SendPong(const Anope::string &servname, const Anope::string &who)
279 {
280 if (servname.empty())
281 UplinkSocket::Message(Me) << "PONG " << who;
282 else
283 UplinkSocket::Message(Me) << "PONG " << servname << " " << who;
284 }
285
SendInvite(const MessageSource & source,const Channel * c,User * u)286 void IRCDProto::SendInvite(const MessageSource &source, const Channel *c, User *u)
287 {
288 UplinkSocket::Message(source) << "INVITE " << u->GetUID() << " " << c->name;
289 }
290
SendPart(User * user,const Channel * chan,const char * fmt,...)291 void IRCDProto::SendPart(User *user, const Channel *chan, const char *fmt, ...)
292 {
293 if (fmt)
294 {
295 va_list args;
296 char buf[BUFSIZE] = "";
297 va_start(args, fmt);
298 vsnprintf(buf, BUFSIZE - 1, fmt, args);
299 va_end(args);
300 SendPartInternal(user, chan, buf);
301 }
302 else
303 SendPartInternal(user, chan, "");
304 }
305
SendGlobops(const MessageSource & source,const char * fmt,...)306 void IRCDProto::SendGlobops(const MessageSource &source, const char *fmt, ...)
307 {
308 va_list args;
309 char buf[BUFSIZE] = "";
310 va_start(args, fmt);
311 vsnprintf(buf, BUFSIZE - 1, fmt, args);
312 va_end(args);
313 SendGlobopsInternal(source, buf);
314 }
315
SendSquit(Server * s,const Anope::string & message)316 void IRCDProto::SendSquit(Server *s, const Anope::string &message)
317 {
318 UplinkSocket::Message() << "SQUIT " << s->GetSID() << " :" << message;
319 }
320
SendNickChange(User * u,const Anope::string & newnick)321 void IRCDProto::SendNickChange(User *u, const Anope::string &newnick)
322 {
323 UplinkSocket::Message(u) << "NICK " << newnick << " " << Anope::CurTime;
324 }
325
SendForceNickChange(User * u,const Anope::string & newnick,time_t when)326 void IRCDProto::SendForceNickChange(User *u, const Anope::string &newnick, time_t when)
327 {
328 UplinkSocket::Message() << "SVSNICK " << u->GetUID() << " " << newnick << " " << when;
329 }
330
SendCTCP(const MessageSource & source,const Anope::string & dest,const char * fmt,...)331 void IRCDProto::SendCTCP(const MessageSource &source, const Anope::string &dest, const char *fmt, ...)
332 {
333 va_list args;
334 char buf[BUFSIZE] = "";
335 va_start(args, fmt);
336 vsnprintf(buf, BUFSIZE - 1, fmt, args);
337 va_end(args);
338 SendCTCPInternal(source, dest, buf);
339 }
340
SendNumeric(int numeric,const Anope::string & dest,const char * fmt,...)341 void IRCDProto::SendNumeric(int numeric, const Anope::string &dest, const char *fmt, ...)
342 {
343 va_list args;
344 char buf[BUFSIZE] = "";
345 va_start(args, fmt);
346 vsnprintf(buf, BUFSIZE - 1, fmt, args);
347 va_end(args);
348 SendNumericInternal(numeric, dest, buf);
349 }
350
IsNickValid(const Anope::string & nick)351 bool IRCDProto::IsNickValid(const Anope::string &nick)
352 {
353 /**
354 * RFC: defination of a valid nick
355 * nickname = ( letter / special ) ( letter / digit / special / "-" )
356 * letter = A-Z / a-z
357 * digit = 0-9
358 * special = [, ], \, `, _, ^, {, |, }
359 **/
360
361 if (nick.empty())
362 return false;
363
364 Anope::string special = "[]\\`_^{|}";
365
366 for (unsigned i = 0; i < nick.length(); ++i)
367 if (!(nick[i] >= 'A' && nick[i] <= 'Z') && !(nick[i] >= 'a' && nick[i] <= 'z')
368 && special.find(nick[i]) == Anope::string::npos
369 && (Config && Config->NickChars.find(nick[i]) == Anope::string::npos)
370 && (!i || (!(nick[i] >= '0' && nick[i] <= '9') && nick[i] != '-')))
371 return false;
372
373 return true;
374 }
375
IsChannelValid(const Anope::string & chan)376 bool IRCDProto::IsChannelValid(const Anope::string &chan)
377 {
378 if (chan.empty() || chan[0] != '#' || chan.length() > Config->GetBlock("networkinfo")->Get<unsigned>("chanlen"))
379 return false;
380
381 if (chan.find_first_of(" ,") != Anope::string::npos)
382 return false;
383
384 return true;
385 }
386
IsIdentValid(const Anope::string & ident)387 bool IRCDProto::IsIdentValid(const Anope::string &ident)
388 {
389 if (ident.empty() || ident.length() > Config->GetBlock("networkinfo")->Get<unsigned>("userlen"))
390 return false;
391
392 for (unsigned i = 0; i < ident.length(); ++i)
393 {
394 const char &c = ident[i];
395
396 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '.' || c == '-')
397 continue;
398
399 return false;
400 }
401
402 return true;
403 }
404
IsHostValid(const Anope::string & host)405 bool IRCDProto::IsHostValid(const Anope::string &host)
406 {
407 if (host.empty() || host.length() > Config->GetBlock("networkinfo")->Get<unsigned>("hostlen"))
408 return false;
409
410 const Anope::string &vhostdisablebe = Config->GetBlock("networkinfo")->Get<const Anope::string>("disallow_start_or_end"),
411 vhostchars = Config->GetBlock("networkinfo")->Get<const Anope::string>("vhost_chars");
412
413 if (vhostdisablebe.find_first_of(host[0]) != Anope::string::npos)
414 return false;
415 else if (vhostdisablebe.find_first_of(host[host.length() - 1]) != Anope::string::npos)
416 return false;
417
418 int dots = 0;
419 for (unsigned i = 0; i < host.length(); ++i)
420 {
421 if (host[i] == '.')
422 ++dots;
423 if (vhostchars.find_first_of(host[i]) == Anope::string::npos)
424 return false;
425 }
426
427 return dots > 0 || Config->GetBlock("networkinfo")->Get<bool>("allow_undotted_vhosts");
428 }
429
SendOper(User * u)430 void IRCDProto::SendOper(User *u)
431 {
432 SendNumericInternal(381, u->GetUID(), ":You are now an IRC operator (set by services)");
433 u->SetMode(NULL, "OPER");
434 }
435
GetMaxListFor(Channel * c)436 unsigned IRCDProto::GetMaxListFor(Channel *c)
437 {
438 return c->HasMode("LBAN") ? 0 : Config->GetBlock("networkinfo")->Get<int>("modelistsize");
439 }
440
NormalizeMask(const Anope::string & mask)441 Anope::string IRCDProto::NormalizeMask(const Anope::string &mask)
442 {
443 if (IsExtbanValid(mask))
444 return mask;
445 return Entry("", mask).GetNUHMask();
446 }
447
MessageSource(const Anope::string & src)448 MessageSource::MessageSource(const Anope::string &src) : source(src), u(NULL), s(NULL)
449 {
450 /* no source for incoming message is our uplink */
451 if (src.empty())
452 this->s = Servers::GetUplink();
453 else if (IRCD->RequiresID || src.find('.') != Anope::string::npos)
454 this->s = Server::Find(src);
455 if (this->s == NULL)
456 this->u = User::Find(src);
457 }
458
MessageSource(User * _u)459 MessageSource::MessageSource(User *_u) : source(_u ? _u->nick : ""), u(_u), s(NULL)
460 {
461 }
462
MessageSource(Server * _s)463 MessageSource::MessageSource(Server *_s) : source(_s ? _s->GetName() : ""), u(NULL), s(_s)
464 {
465 }
466
GetName() const467 const Anope::string &MessageSource::GetName() const
468 {
469 if (this->s)
470 return this->s->GetName();
471 else if (this->u)
472 return this->u->nick;
473 else
474 return this->source;
475 }
476
GetSource() const477 const Anope::string &MessageSource::GetSource() const
478 {
479 return this->source;
480 }
481
GetUser() const482 User *MessageSource::GetUser() const
483 {
484 return this->u;
485 }
486
GetBot() const487 BotInfo *MessageSource::GetBot() const
488 {
489 return BotInfo::Find(this->GetName(), true);
490 }
491
GetServer() const492 Server *MessageSource::GetServer() const
493 {
494 return this->s;
495 }
496
IRCDMessage(Module * o,const Anope::string & n,unsigned p)497 IRCDMessage::IRCDMessage(Module *o, const Anope::string &n, unsigned p) : Service(o, "IRCDMessage", o->name + "/" + n.lower()), name(n), param_count(p)
498 {
499 }
500
GetParamCount() const501 unsigned IRCDMessage::GetParamCount() const
502 {
503 return this->param_count;
504 }
505
Run(MessageSource & source,const std::vector<Anope::string> & params,const Anope::map<Anope::string> & tags)506 void IRCDMessage::Run(MessageSource &source, const std::vector<Anope::string> ¶ms, const Anope::map<Anope::string> &tags)
507 {
508 // Most IRCds don't support message tags yet so use the tagless variant.
509 Run(source, params);
510 }
511
512