1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2017 B00mX0r <b00mx0r@aureus.pw>
5  *   Copyright (C) 2013-2014, 2016-2020 Sadie Powell <sadie@witchery.services>
6  *   Copyright (C) 2013 Adam <Adam@anope.org>
7  *   Copyright (C) 2012-2016, 2018 Attila Molnar <attilamolnar@hush.com>
8  *   Copyright (C) 2012, 2019 Robby <robby@chatbelgie.be>
9  *   Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
10  *   Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
11  *   Copyright (C) 2006-2009 Robin Burchell <robin+git@viroteck.net>
12  *   Copyright (C) 2006-2008, 2010 Craig Edwards <brain@inspircd.org>
13  *
14  * This file is part of InspIRCd.  InspIRCd is free software: you can
15  * redistribute it and/or modify it under the terms of the GNU General Public
16  * License as published by the Free Software Foundation, version 2.
17  *
18  * This program is distributed in the hope that it will be useful, but WITHOUT
19  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
21  * details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
25  */
26 
27 
28 #include "inspircd.h"
29 #include "listmode.h"
30 
31 namespace
32 {
33 	ChanModeReference ban(NULL, "ban");
34 }
35 
Channel(const std::string & cname,time_t ts)36 Channel::Channel(const std::string &cname, time_t ts)
37 	: name(cname), age(ts), topicset(0)
38 {
39 	if (!ServerInstance->chanlist.insert(std::make_pair(cname, this)).second)
40 		throw CoreException("Cannot create duplicate channel " + cname);
41 }
42 
SetMode(ModeHandler * mh,bool on)43 void Channel::SetMode(ModeHandler* mh, bool on)
44 {
45 	if (mh && mh->GetId() != ModeParser::MODEID_MAX)
46 		modes[mh->GetId()] = on;
47 }
48 
SetTopic(User * u,const std::string & ntopic,time_t topicts,const std::string * setter)49 void Channel::SetTopic(User* u, const std::string& ntopic, time_t topicts, const std::string* setter)
50 {
51 	// Send a TOPIC message to the channel only if the new topic text differs
52 	if (this->topic != ntopic)
53 	{
54 		this->topic = ntopic;
55 		ClientProtocol::Messages::Topic topicmsg(u, this, this->topic);
56 		Write(ServerInstance->GetRFCEvents().topic, topicmsg);
57 	}
58 
59 	// Always update setter and set time
60 	if (!setter)
61 		setter = ServerInstance->Config->FullHostInTopic ? &u->GetFullHost() : &u->nick;
62 	this->setby.assign(*setter, 0, ServerInstance->Config->Limits.GetMaxMask());
63 	this->topicset = topicts;
64 
65 	FOREACH_MOD(OnPostTopicChange, (u, this, this->topic));
66 }
67 
AddUser(User * user)68 Membership* Channel::AddUser(User* user)
69 {
70 	std::pair<MemberMap::iterator, bool> ret = userlist.insert(std::make_pair(user, insp::aligned_storage<Membership>()));
71 	if (!ret.second)
72 		return NULL;
73 
74 	Membership* memb = new(ret.first->second) Membership(user, this);
75 	return memb;
76 }
77 
DelUser(User * user)78 void Channel::DelUser(User* user)
79 {
80 	MemberMap::iterator it = userlist.find(user);
81 	if (it != userlist.end())
82 		DelUser(it);
83 }
84 
CheckDestroy()85 void Channel::CheckDestroy()
86 {
87 	if (!userlist.empty())
88 		return;
89 
90 	ModResult res;
91 	FIRST_MOD_RESULT(OnChannelPreDelete, res, (this));
92 	if (res == MOD_RES_DENY)
93 		return;
94 
95 	// If the channel isn't in chanlist then it is already in the cull list, don't add it again
96 	chan_hash::iterator iter = ServerInstance->chanlist.find(this->name);
97 	if ((iter == ServerInstance->chanlist.end()) || (iter->second != this))
98 		return;
99 
100 	FOREACH_MOD(OnChannelDelete, (this));
101 	ServerInstance->chanlist.erase(iter);
102 	ServerInstance->GlobalCulls.AddItem(this);
103 }
104 
DelUser(const MemberMap::iterator & membiter)105 void Channel::DelUser(const MemberMap::iterator& membiter)
106 {
107 	Membership* memb = membiter->second;
108 	memb->cull();
109 	memb->~Membership();
110 	userlist.erase(membiter);
111 
112 	// If this channel became empty then it should be removed
113 	CheckDestroy();
114 }
115 
GetUser(User * user)116 Membership* Channel::GetUser(User* user)
117 {
118 	MemberMap::iterator i = userlist.find(user);
119 	if (i == userlist.end())
120 		return NULL;
121 	return i->second;
122 }
123 
SetDefaultModes()124 void Channel::SetDefaultModes()
125 {
126 	ServerInstance->Logs->Log("CHANNELS", LOG_DEBUG, "SetDefaultModes %s",
127 		ServerInstance->Config->DefaultModes.c_str());
128 	irc::spacesepstream list(ServerInstance->Config->DefaultModes);
129 	std::string modeseq;
130 	std::string parameter;
131 
132 	list.GetToken(modeseq);
133 
134 	for (std::string::iterator n = modeseq.begin(); n != modeseq.end(); ++n)
135 	{
136 		ModeHandler* mode = ServerInstance->Modes->FindMode(*n, MODETYPE_CHANNEL);
137 		if (mode)
138 		{
139 			if (mode->IsPrefixMode())
140 				continue;
141 
142 			if (mode->NeedsParam(true))
143 			{
144 				list.GetToken(parameter);
145 				// If the parameter begins with a ':' then it's invalid
146 				if (parameter.c_str()[0] == ':')
147 					continue;
148 			}
149 			else
150 				parameter.clear();
151 
152 			if ((mode->NeedsParam(true)) && (parameter.empty()))
153 				continue;
154 
155 			mode->OnModeChange(ServerInstance->FakeClient, ServerInstance->FakeClient, this, parameter, true);
156 		}
157 	}
158 }
159 
160 /*
161  * add a channel to a user, creating the record for it if needed and linking
162  * it to the user record
163  */
JoinUser(LocalUser * user,std::string cname,bool override,const std::string & key)164 Channel* Channel::JoinUser(LocalUser* user, std::string cname, bool override, const std::string& key)
165 {
166 	if (user->registered != REG_ALL)
167 	{
168 		ServerInstance->Logs->Log("CHANNELS", LOG_DEBUG, "Attempted to join unregistered user " + user->uuid + " to channel " + cname);
169 		return NULL;
170 	}
171 
172 	/*
173 	 * We don't restrict the number of channels that remote users or users that are override-joining may be in.
174 	 * We restrict local users to <connect:maxchans> channels.
175 	 * We restrict local operators to <oper:maxchans> channels.
176 	 * This is a lot more logical than how it was formerly. -- w00t
177 	 */
178 	if (!override)
179 	{
180 		unsigned int maxchans = user->GetClass()->maxchans;
181 		if (!maxchans)
182 			maxchans = ServerInstance->Config->MaxChans;
183 		if (user->IsOper())
184 		{
185 			unsigned int opermaxchans = ConvToNum<unsigned int>(user->oper->getConfig("maxchans"));
186 			// If not set, use 2.0's <channels:opers>, if that's not set either, use limit from CC
187 			if (!opermaxchans && user->HasPrivPermission("channels/high-join-limit"))
188 				opermaxchans = ServerInstance->Config->OperMaxChans;
189 			if (opermaxchans)
190 				maxchans = opermaxchans;
191 		}
192 		if (user->chans.size() >= maxchans)
193 		{
194 			user->WriteNumeric(ERR_TOOMANYCHANNELS, cname, "You are on too many channels");
195 			return NULL;
196 		}
197 	}
198 
199 	// Crop channel name if it's too long
200 	if (cname.length() > ServerInstance->Config->Limits.ChanMax)
201 		cname.resize(ServerInstance->Config->Limits.ChanMax);
202 
203 	Channel* chan = ServerInstance->FindChan(cname);
204 	bool created_by_local = (chan == NULL); // Flag that will be passed to modules in the OnUserJoin() hook later
205 	std::string privs; // Prefix mode(letter)s to give to the joining user
206 
207 	if (!chan)
208 	{
209 		privs = ServerInstance->Config->DefaultModes.substr(0, ServerInstance->Config->DefaultModes.find(' '));
210 
211 		if (override == false)
212 		{
213 			// Ask the modules whether they're ok with the join, pass NULL as Channel* as the channel is yet to be created
214 			ModResult MOD_RESULT;
215 			FIRST_MOD_RESULT(OnUserPreJoin, MOD_RESULT, (user, NULL, cname, privs, key));
216 			if (MOD_RESULT == MOD_RES_DENY)
217 				return NULL; // A module wasn't happy with the join, abort
218 		}
219 
220 		chan = new Channel(cname, ServerInstance->Time());
221 		// Set the default modes on the channel (<options:defaultmodes>)
222 		chan->SetDefaultModes();
223 	}
224 	else
225 	{
226 		/* Already on the channel */
227 		if (chan->HasUser(user))
228 			return NULL;
229 
230 		if (override == false)
231 		{
232 			ModResult MOD_RESULT;
233 			FIRST_MOD_RESULT(OnUserPreJoin, MOD_RESULT, (user, chan, cname, privs, key));
234 
235 			// A module explicitly denied the join and (hopefully) generated a message
236 			// describing the situation, so we may stop here without sending anything
237 			if (MOD_RESULT == MOD_RES_DENY)
238 				return NULL;
239 
240 			// If no module returned MOD_RES_DENY or MOD_RES_ALLOW (which is the case
241 			// most of the time) then proceed to check channel bans.
242 			//
243 			// If a module explicitly allowed the join (by returning MOD_RES_ALLOW),
244 			// then this entire section is skipped
245 			if (MOD_RESULT == MOD_RES_PASSTHRU)
246 			{
247 				if (chan->IsBanned(user))
248 				{
249 					user->WriteNumeric(ERR_BANNEDFROMCHAN, chan->name, "Cannot join channel (you're banned)");
250 					return NULL;
251 				}
252 			}
253 		}
254 	}
255 
256 	// We figured that this join is allowed and also created the
257 	// channel if it didn't exist before, now do the actual join
258 	chan->ForceJoin(user, &privs, false, created_by_local);
259 	return chan;
260 }
261 
ForceJoin(User * user,const std::string * privs,bool bursting,bool created_by_local)262 Membership* Channel::ForceJoin(User* user, const std::string* privs, bool bursting, bool created_by_local)
263 {
264 	if (IS_SERVER(user))
265 	{
266 		ServerInstance->Logs->Log("CHANNELS", LOG_DEBUG, "Attempted to join server user " + user->uuid + " to channel " + this->name);
267 		return NULL;
268 	}
269 
270 	Membership* memb = this->AddUser(user);
271 	if (!memb)
272 		return NULL; // Already on the channel
273 
274 	user->chans.push_front(memb);
275 
276 	if (privs)
277 	{
278 		// If the user was granted prefix modes (in the OnUserPreJoin hook, or they're a
279 		// remote user and their own server set the modes), then set them internally now
280 		for (std::string::const_iterator i = privs->begin(); i != privs->end(); ++i)
281 		{
282 			PrefixMode* mh = ServerInstance->Modes->FindPrefixMode(*i);
283 			if (mh)
284 			{
285 				std::string nick = user->nick;
286 				// Set the mode on the user
287 				mh->OnModeChange(ServerInstance->FakeClient, NULL, this, nick, true);
288 			}
289 		}
290 	}
291 
292 	// Tell modules about this join, they have the chance now to populate except_list with users we won't send the JOIN (and possibly MODE) to
293 	CUList except_list;
294 	FOREACH_MOD(OnUserJoin, (memb, bursting, created_by_local, except_list));
295 
296 	ClientProtocol::Events::Join joinevent(memb);
297 	this->Write(joinevent, 0, except_list);
298 
299 	FOREACH_MOD(OnPostJoin, (memb));
300 	return memb;
301 }
302 
IsBanned(User * user)303 bool Channel::IsBanned(User* user)
304 {
305 	ModResult result;
306 	FIRST_MOD_RESULT(OnCheckChannelBan, result, (user, this));
307 
308 	if (result != MOD_RES_PASSTHRU)
309 		return (result == MOD_RES_DENY);
310 
311 	ListModeBase* banlm = static_cast<ListModeBase*>(*ban);
312 	if (!banlm)
313 		return false;
314 
315 	const ListModeBase::ModeList* bans = banlm->GetList(this);
316 	if (bans)
317 	{
318 		for (ListModeBase::ModeList::const_iterator it = bans->begin(); it != bans->end(); it++)
319 		{
320 			if (CheckBan(user, it->mask))
321 				return true;
322 		}
323 	}
324 	return false;
325 }
326 
CheckBan(User * user,const std::string & mask)327 bool Channel::CheckBan(User* user, const std::string& mask)
328 {
329 	ModResult result;
330 	FIRST_MOD_RESULT(OnCheckBan, result, (user, this, mask));
331 	if (result != MOD_RES_PASSTHRU)
332 		return (result == MOD_RES_DENY);
333 
334 	// extbans were handled above, if this is one it obviously didn't match
335 	if ((mask.length() <= 2) || (mask[1] == ':'))
336 		return false;
337 
338 	std::string::size_type at = mask.find('@');
339 	if (at == std::string::npos)
340 		return false;
341 
342 	const std::string nickIdent = user->nick + "!" + user->ident;
343 	std::string prefix(mask, 0, at);
344 	if (InspIRCd::Match(nickIdent, prefix, NULL))
345 	{
346 		std::string suffix(mask, at + 1);
347 		if (InspIRCd::Match(user->GetRealHost(), suffix, NULL) ||
348 			InspIRCd::Match(user->GetDisplayedHost(), suffix, NULL) ||
349 			InspIRCd::MatchCIDR(user->GetIPString(), suffix, NULL))
350 			return true;
351 	}
352 	return false;
353 }
354 
GetExtBanStatus(User * user,char type)355 ModResult Channel::GetExtBanStatus(User *user, char type)
356 {
357 	ModResult rv;
358 	FIRST_MOD_RESULT(OnExtBanCheck, rv, (user, this, type));
359 	if (rv != MOD_RES_PASSTHRU)
360 		return rv;
361 
362 	ListModeBase* banlm = static_cast<ListModeBase*>(*ban);
363 	if (!banlm)
364 		return MOD_RES_PASSTHRU;
365 
366 	const ListModeBase::ModeList* bans = banlm->GetList(this);
367 	if (bans)
368 	{
369 		for (ListModeBase::ModeList::const_iterator it = bans->begin(); it != bans->end(); ++it)
370 		{
371 			if (it->mask.length() <= 2 || it->mask[0] != type || it->mask[1] != ':')
372 				continue;
373 
374 			if (CheckBan(user, it->mask.substr(2)))
375 				return MOD_RES_DENY;
376 		}
377 	}
378 	return MOD_RES_PASSTHRU;
379 }
380 
381 /* Channel::PartUser
382  * Remove a channel from a users record, remove the reference to the Membership object
383  * from the channel and destroy it.
384  */
PartUser(User * user,std::string & reason)385 bool Channel::PartUser(User* user, std::string& reason)
386 {
387 	MemberMap::iterator membiter = userlist.find(user);
388 
389 	if (membiter == userlist.end())
390 		return false;
391 
392 	Membership* memb = membiter->second;
393 	CUList except_list;
394 	FOREACH_MOD(OnUserPart, (memb, reason, except_list));
395 
396 	ClientProtocol::Messages::Part partmsg(memb, reason);
397 	Write(ServerInstance->GetRFCEvents().part, partmsg, 0, except_list);
398 
399 	// Remove this channel from the user's chanlist
400 	user->chans.erase(memb);
401 	// Remove the Membership from this channel's userlist and destroy it
402 	this->DelUser(membiter);
403 
404 	return true;
405 }
406 
KickUser(User * src,const MemberMap::iterator & victimiter,const std::string & reason)407 void Channel::KickUser(User* src, const MemberMap::iterator& victimiter, const std::string& reason)
408 {
409 	Membership* memb = victimiter->second;
410 	CUList except_list;
411 	FOREACH_MOD(OnUserKick, (src, memb, reason, except_list));
412 
413 	ClientProtocol::Messages::Kick kickmsg(src, memb, reason);
414 	Write(ServerInstance->GetRFCEvents().kick, kickmsg, 0, except_list);
415 
416 	memb->user->chans.erase(memb);
417 	this->DelUser(victimiter);
418 }
419 
Write(ClientProtocol::Event & protoev,char status,const CUList & except_list)420 void Channel::Write(ClientProtocol::Event& protoev, char status, const CUList& except_list)
421 {
422 	unsigned int minrank = 0;
423 	if (status)
424 	{
425 		PrefixMode* mh = ServerInstance->Modes->FindPrefix(status);
426 		if (mh)
427 			minrank = mh->GetPrefixRank();
428 	}
429 	for (MemberMap::iterator i = userlist.begin(); i != userlist.end(); i++)
430 	{
431 		LocalUser* user = IS_LOCAL(i->first);
432 		if ((user) && (!except_list.count(user)))
433 		{
434 			/* User doesn't have the status we're after */
435 			if (minrank && i->second->getRank() < minrank)
436 				continue;
437 
438 			user->Send(protoev);
439 		}
440 	}
441 }
442 
ChanModes(bool showsecret)443 const char* Channel::ChanModes(bool showsecret)
444 {
445 	static std::string scratch;
446 	std::string sparam;
447 
448 	scratch.clear();
449 
450 	/* This was still iterating up to 190, Channel::modes is only 64 elements -- Om */
451 	for(int n = 0; n < 64; n++)
452 	{
453 		ModeHandler* mh = ServerInstance->Modes->FindMode(n + 65, MODETYPE_CHANNEL);
454 		if (mh && IsModeSet(mh))
455 		{
456 			scratch.push_back(n + 65);
457 
458 			ParamModeBase* pm = mh->IsParameterMode();
459 			if (!pm)
460 				continue;
461 
462 			if (pm->IsParameterSecret() && !showsecret)
463 			{
464 				sparam += " <" + pm->name + ">";
465 			}
466 			else
467 			{
468 				sparam += ' ';
469 				pm->GetParameter(this, sparam);
470 			}
471 		}
472 	}
473 
474 	scratch += sparam;
475 	return scratch.c_str();
476 }
477 
WriteNotice(const std::string & text,char status)478 void Channel::WriteNotice(const std::string& text, char status)
479 {
480 	ClientProtocol::Messages::Privmsg privmsg(ClientProtocol::Messages::Privmsg::nocopy, ServerInstance->FakeClient, this, text, MSG_NOTICE, status);
481 	Write(ServerInstance->GetRFCEvents().privmsg, privmsg);
482 }
483 
WriteRemoteNotice(const std::string & text,char status)484 void Channel::WriteRemoteNotice(const std::string& text, char status)
485 {
486 	WriteNotice(text, status);
487 	ServerInstance->PI->SendMessage(this, status, text, MSG_NOTICE);
488 }
489 
490 /* returns the status character for a given user on a channel, e.g. @ for op,
491  * % for halfop etc. If the user has several modes set, the highest mode
492  * the user has must be returned.
493  */
GetPrefixChar() const494 char Membership::GetPrefixChar() const
495 {
496 	char pf = 0;
497 	unsigned int bestrank = 0;
498 
499 	for (std::string::const_iterator i = modes.begin(); i != modes.end(); ++i)
500 	{
501 		PrefixMode* mh = ServerInstance->Modes->FindPrefixMode(*i);
502 		if (mh && mh->GetPrefixRank() > bestrank && mh->GetPrefix())
503 		{
504 			bestrank = mh->GetPrefixRank();
505 			pf = mh->GetPrefix();
506 		}
507 	}
508 	return pf;
509 }
510 
getRank()511 unsigned int Membership::getRank()
512 {
513 	char mchar = modes.c_str()[0];
514 	unsigned int rv = 0;
515 	if (mchar)
516 	{
517 		PrefixMode* mh = ServerInstance->Modes->FindPrefixMode(mchar);
518 		if (mh)
519 			rv = mh->GetPrefixRank();
520 	}
521 	return rv;
522 }
523 
GetAllPrefixChars() const524 std::string Membership::GetAllPrefixChars() const
525 {
526 	std::string ret;
527 	for (std::string::const_iterator i = modes.begin(); i != modes.end(); ++i)
528 	{
529 		PrefixMode* mh = ServerInstance->Modes->FindPrefixMode(*i);
530 		if (mh && mh->GetPrefix())
531 			ret.push_back(mh->GetPrefix());
532 	}
533 
534 	return ret;
535 }
536 
GetPrefixValue(User * user)537 unsigned int Channel::GetPrefixValue(User* user)
538 {
539 	MemberMap::iterator m = userlist.find(user);
540 	if (m == userlist.end())
541 		return 0;
542 	return m->second->getRank();
543 }
544 
SetPrefix(PrefixMode * delta_mh,bool adding)545 bool Membership::SetPrefix(PrefixMode* delta_mh, bool adding)
546 {
547 	char prefix = delta_mh->GetModeChar();
548 	for (unsigned int i = 0; i < modes.length(); i++)
549 	{
550 		char mchar = modes[i];
551 		PrefixMode* mh = ServerInstance->Modes->FindPrefixMode(mchar);
552 		if (mh && mh->GetPrefixRank() <= delta_mh->GetPrefixRank())
553 		{
554 			modes = modes.substr(0,i) +
555 				(adding ? std::string(1, prefix) : "") +
556 				modes.substr(mchar == prefix ? i+1 : i);
557 			return adding != (mchar == prefix);
558 		}
559 	}
560 	if (adding)
561 		modes.push_back(prefix);
562 	return adding;
563 }
564 
565 
WriteNotice(const std::string & text) const566 void Membership::WriteNotice(const std::string& text) const
567 {
568 	LocalUser* const localuser = IS_LOCAL(user);
569 	if (!localuser)
570 		return;
571 
572 	ClientProtocol::Messages::Privmsg privmsg(ClientProtocol::Messages::Privmsg::nocopy, ServerInstance->FakeClient, this->chan, text, MSG_NOTICE);
573 	localuser->Send(ServerInstance->GetRFCEvents().privmsg, privmsg);
574 }
575