unrealircd

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

nick.c (40135B)

      1 /*
      2  *   IRC - Internet Relay Chat, src/modules/nick.c
      3  *   (C) 1999-2005 The UnrealIRCd Team
      4  *
      5  *   See file AUTHORS in IRC package for additional names of
      6  *   the programmers.
      7  *
      8  *   This program is free software; you can redistribute it and/or modify
      9  *   it under the terms of the GNU General Public License as published by
     10  *   the Free Software Foundation; either version 1, or (at your option)
     11  *   any later version.
     12  *
     13  *   This program is distributed in the hope that it will be useful,
     14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16  *   GNU General Public License for more details.
     17  *
     18  *   You should have received a copy of the GNU General Public License
     19  *   along with this program; if not, write to the Free Software
     20  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     21  */
     22 
     23 #include "unrealircd.h"
     24 
     25 ModuleHeader MOD_HEADER
     26   = {
     27 	"nick",
     28 	"5.0",
     29 	"command /nick",
     30 	"UnrealIRCd Team",
     31 	"unrealircd-6",
     32     };
     33 
     34 /* Defines */
     35 
     36 #define NICKCOL_EQUAL         0
     37 #define NICKCOL_NEW_WON       1
     38 #define NICKCOL_EXISTING_WON  2
     39 
     40 /* Assume that on collision a NICK is in flight and the other server will take
     41  * the exact same decision we would do, and thus we don't send a KILL to cptr?
     42  * This works great with this code, seems to kill the correct person and not
     43  * cause desyncs even without UID/SID. HOWEVER.. who knows what code the other servers run?
     44  * Should use UID/SID anyway, then this whole problem doesn't exist.
     45  */
     46 #define ASSUME_NICK_IN_FLIGHT
     47 
     48 /* Variables */
     49 static char spamfilter_user[NICKLEN + USERLEN + HOSTLEN + REALLEN + 64];
     50 
     51 /* Forward declarations */
     52 CMD_FUNC(cmd_nick);
     53 CMD_FUNC(cmd_nick_local);
     54 CMD_FUNC(cmd_nick_remote);
     55 CMD_FUNC(cmd_uid);
     56 int _register_user(Client *client);
     57 void nick_collision(Client *cptr, const char *newnick, const char *newid, Client *new, Client *existing, int type);
     58 int AllowClient(Client *client);
     59 
     60 MOD_TEST()
     61 {
     62 	MARK_AS_OFFICIAL_MODULE(modinfo);
     63 	EfunctionAdd(modinfo->handle, EFUNC_REGISTER_USER, _register_user);
     64 	return MOD_SUCCESS;
     65 }
     66 
     67 MOD_INIT()
     68 {
     69 	CommandAdd(modinfo->handle, "NICK", cmd_nick, MAXPARA, CMD_USER|CMD_SERVER|CMD_UNREGISTERED);
     70 	CommandAdd(modinfo->handle, "UID", cmd_uid, MAXPARA, CMD_SERVER);
     71 	MARK_AS_OFFICIAL_MODULE(modinfo);
     72 	return MOD_SUCCESS;
     73 }
     74 
     75 MOD_LOAD()
     76 {
     77 	return MOD_SUCCESS;
     78 }
     79 
     80 MOD_UNLOAD()
     81 {
     82 	return MOD_SUCCESS;
     83 }
     84 
     85 /** Hmm.. don't we already have such a function? */
     86 void set_user_modes_dont_spread(Client *client, const char *umode)
     87 {
     88 	const char *args[4];
     89 
     90 	args[0] = client->name;
     91 	args[1] = client->name;
     92 	args[2] = umode;
     93 	args[3] = NULL;
     94 
     95 	dontspread = 1;
     96 	do_cmd(client, NULL, "MODE", 3, args);
     97 	dontspread = 0;
     98 }
     99 
    100 /** Remote client (already fully registered) changing their nick */
    101 CMD_FUNC(cmd_nick_remote)
    102 {
    103 	TKL *tklban;
    104 	int ishold;
    105 	Client *acptr;
    106 	char nick[NICKLEN + 2];
    107 	char oldnick[NICKLEN + 1];
    108 	time_t lastnick = 0;
    109 	int differ = 1;
    110 	unsigned char removemoder = (client->umodes & UMODE_REGNICK) ? 1 : 0;
    111 	MessageTag *mtags = NULL;
    112 
    113 	/* 'client' is always the fully registered user doing the nick change */
    114 
    115 	strlcpy(nick, parv[1], NICKLEN + 1);
    116 	strlcpy(oldnick, client->name, sizeof(oldnick));
    117 
    118 	if (parc > 2)
    119 		lastnick = atol(parv[2]);
    120 
    121 	if (!do_remote_nick_name(nick) || !strcasecmp("ircd", nick) || !strcasecmp("irc", nick))
    122 	{
    123 		ircstats.is_kill++;
    124 		unreal_log(ULOG_ERROR, "nick", "BAD_NICK_REMOTE", client,
    125 		           "Server link $server tried to change '$client' to bad nick '$nick' -- rejected.",
    126 		           log_data_string("nick", parv[1]),
    127 		           log_data_client("server", client->uplink));
    128 		mtags = NULL;
    129 		new_message(client, NULL, &mtags);
    130 		sendto_one(client, mtags, ":%s KILL %s :Illegal nick name", me.id, client->id);
    131 		SetKilled(client);
    132 		exit_client(client, mtags, "Illegal nick name");
    133 		free_message_tags(mtags);
    134 		mtags = NULL;
    135 		return;
    136 	}
    137 
    138 	/* Check Q-lines / ban nick */
    139 	if (!IsULine(client) && (tklban = find_qline(client, nick, &ishold)) && !ishold)
    140 	{
    141 		unreal_log(ULOG_INFO, "nick", "QLINE_NICK_REMOTE", client,
    142 			   "Banned nick $nick [$ip] from server $server ($reason)",
    143 			   log_data_string("nick", parv[1]),
    144 			   log_data_string("ip", GetIP(client)),
    145 			   log_data_client("server", client->uplink),
    146 			   log_data_string("reason", tklban->ptr.nameban->reason));
    147 		/* Let it through */
    148 	}
    149 
    150 	if ((acptr = find_client(nick, NULL)))
    151 	{
    152 		/* If existing nick is still in handshake, kill it */
    153 		if (IsUnknown(acptr) && MyConnect(acptr))
    154 		{
    155 			SetKilled(acptr);
    156 			exit_client(acptr, NULL, "Overridden");
    157 		} else
    158 		if (acptr == client)
    159 		{
    160 			/* 100% identical? Must be a bug, but ok */
    161 			if (!strcmp(acptr->name, nick))
    162 				return;
    163 			/* Allows change of case in their nick */
    164 			removemoder = 0; /* don't set the user -r */
    165 		} else
    166 		{
    167 			/*
    168 			   ** A NICK change has collided (e.g. message type ":old NICK new").
    169 			 */
    170 			differ = (mycmp(acptr->user->username, client->user->username) ||
    171 			          mycmp(acptr->user->realhost, client->user->realhost));
    172 
    173 			if (!(parc > 2) || lastnick == acptr->lastnick)
    174 			{
    175 				nick_collision(client, parv[1], client->id, client, acptr, NICKCOL_EQUAL);
    176 				return; /* Now that I killed them both, ignore the NICK */
    177 			} else
    178 			if ((differ && (acptr->lastnick > lastnick)) ||
    179 			    (!differ && (acptr->lastnick < lastnick)))
    180 			{
    181 				nick_collision(client, parv[1], client->id, client, acptr, NICKCOL_NEW_WON);
    182 				/* fallthrough: their user won, continue and proceed with the nick change */
    183 			} else
    184 			if ((differ && (acptr->lastnick < lastnick)) ||
    185 			    (!differ && (acptr->lastnick > lastnick)))
    186 			{
    187 				nick_collision(client, parv[1], client->id, client, acptr, NICKCOL_EXISTING_WON);
    188 				return; /* their user lost, ignore the NICK */
    189 			} else
    190 			{
    191 				return;		/* just in case */
    192 			}
    193 		}
    194 	}
    195 
    196 	mtags = NULL;
    197 
    198 	if (!IsULine(client))
    199 	{
    200 		unreal_log(ULOG_INFO, "nick", "REMOTE_NICK_CHANGE", client,
    201 		           "Client $client.details has changed their nickname to $new_nick",
    202 		           log_data_string("new_nick", nick));
    203 	}
    204 
    205 	new_message(client, recv_mtags, &mtags);
    206 	RunHook(HOOKTYPE_REMOTE_NICKCHANGE, client, mtags, nick);
    207 	client->lastnick = lastnick ? lastnick : TStime();
    208 	add_history(client, 1, WHOWAS_EVENT_NICK_CHANGE);
    209 	sendto_server(client, 0, 0, mtags, ":%s NICK %s %lld",
    210 	    client->id, nick, (long long)client->lastnick);
    211 	sendto_local_common_channels(client, client, 0, mtags, ":%s NICK :%s", client->name, nick);
    212 	if (removemoder)
    213 		client->umodes &= ~UMODE_REGNICK;
    214 
    215 	/* Finally set new nick name. */
    216 	del_from_client_hash_table(client->name, client);
    217 	strlcpy(client->name, nick, sizeof(client->name));
    218 	add_to_client_hash_table(nick, client);
    219 
    220 	RunHook(HOOKTYPE_POST_REMOTE_NICKCHANGE, client, mtags, oldnick);
    221 	free_message_tags(mtags);
    222 }
    223 
    224 /* Local user: either setting their nick for the first time (registration)
    225  * or changing their nick (fully registered already, or not)
    226  */
    227 CMD_FUNC(cmd_nick_local)
    228 {
    229 	TKL *tklban;
    230 	int ishold;
    231 	Client *acptr;
    232 	char nick[NICKLEN + 2];
    233 	char oldnick[NICKLEN + 1];
    234 	char descbuf[BUFSIZE];
    235 	Membership *mp;
    236 	int newuser = 0;
    237 	unsigned char removemoder = (client->umodes & UMODE_REGNICK) ? 1 : 0;
    238 	Hook *h;
    239 	int ret;
    240 
    241 	strlcpy(oldnick, client->name, sizeof(oldnick));
    242 
    243 	/* Enforce minimum nick length */
    244 	if (iConf.min_nick_length && !IsOper(client) && !IsULine(client) && strlen(parv[1]) < iConf.min_nick_length)
    245 	{
    246 		snprintf(descbuf, sizeof descbuf, "A minimum length of %d chars is required", iConf.min_nick_length);
    247 		sendnumeric(client, ERR_ERRONEUSNICKNAME, parv[1], descbuf);
    248 		return;
    249 	}
    250 
    251 	/* Enforce maximum nick length */
    252 	strlcpy(nick, parv[1], iConf.nick_length + 1);
    253 
    254 	/* Check if this is a valid nick name */
    255 	if (!do_nick_name(nick))
    256 	{
    257 		sendnumeric(client, ERR_ERRONEUSNICKNAME, parv[1], "Illegal characters");
    258 		return;
    259 	}
    260 
    261 	/* Check for collisions / in use */
    262 	if (!strcasecmp("ircd", nick) || !strcasecmp("irc", nick))
    263 	{
    264 		sendnumeric(client, ERR_ERRONEUSNICKNAME, nick, "Reserved for internal IRCd purposes");
    265 		return;
    266 	}
    267 
    268 	if (MyUser(client))
    269 	{
    270 		/* Local client changing nick: check spamfilter */
    271 		spamfilter_build_user_string(spamfilter_user, nick, client);
    272 		if (match_spamfilter(client, spamfilter_user, SPAMF_USER, "NICK", NULL, 0, NULL))
    273 			return;
    274 	}
    275 
    276 	/* Check Q-lines / ban nick */
    277 	if (!IsULine(client) && (tklban = find_qline(client, nick, &ishold)))
    278 	{
    279 		if (ishold)
    280 		{
    281 			sendnumeric(client, ERR_ERRONEUSNICKNAME, nick, tklban->ptr.nameban->reason);
    282 			return;
    283 		}
    284 		if (!ValidatePermissionsForPath("immune:server-ban:ban-nick",client,NULL,NULL,nick))
    285 		{
    286 			add_fake_lag(client, 4000); /* lag them up */
    287 			sendnumeric(client, ERR_ERRONEUSNICKNAME, nick, tklban->ptr.nameban->reason);
    288 			unreal_log(ULOG_INFO, "nick", "QLINE_NICK_LOCAL_ATTEMPT", client,
    289 				   "Attempt to use banned nick $nick [$ip] blocked ($reason)",
    290 				   log_data_string("nick", parv[1]),
    291 				   log_data_string("ip", GetIP(client)),
    292 				   log_data_client("server", client->uplink),
    293 				   log_data_string("reason", tklban->ptr.nameban->reason));
    294 			return;	/* NICK message ignored */
    295 		}
    296 		/* fallthrough for ircops that have sufficient privileges */
    297 	}
    298 
    299 	if (!ValidatePermissionsForPath("immune:nick-flood",client,NULL,NULL,NULL))
    300 		add_fake_lag(client, 3000);
    301 
    302 	if ((acptr = find_client(nick, NULL)))
    303 	{
    304 		/* Shouldn't be possible since dot is disallowed: */
    305 		if (IsServer(acptr))
    306 		{
    307 			sendnumeric(client, ERR_NICKNAMEINUSE, nick);
    308 			return;
    309 		}
    310 		if (acptr == client)
    311 		{
    312 			/* New nick is exactly the same as the old nick? */
    313 			if (!strcmp(acptr->name, nick))
    314 				return;
    315 			/* Changing cAsE */
    316 			removemoder = 0;
    317 		} else
    318 		/* Collision with a nick of a session that is still in handshake */
    319 		if (IsUnknown(acptr) && MyConnect(acptr))
    320 		{
    321 			/* Kill the other connection that is still in progress */
    322 			SetKilled(acptr);
    323 			exit_client(acptr, NULL, "Overridden");
    324 		} else
    325 		{
    326 			sendnumeric(client, ERR_NICKNAMEINUSE, nick);
    327 			return;	/* NICK message ignored */
    328 		}
    329 	}
    330 
    331 	/* set::anti-flood::nick-flood */
    332 	if (client->user &&
    333 	    !ValidatePermissionsForPath("immune:nick-flood",client,NULL,NULL,NULL) &&
    334 	    flood_limit_exceeded(client, FLD_NICK))
    335 	{
    336 		/* Throttle... */
    337 		sendnumeric(client, ERR_NCHANGETOOFAST, nick);
    338 		return;
    339 	}
    340 
    341 	/* New local client? */
    342 	if (!client->name[0])
    343 	{
    344 		newuser = 1;
    345 
    346 		if (iConf.ping_cookie)
    347 		{
    348 			/*
    349 			 * Client setting NICK the first time.
    350 			 *
    351 			 * Generate a random string for them to pong with.
    352 			 */
    353 			client->local->nospoof = getrandom32();
    354 
    355 			sendto_one(client, NULL, "PING :%X", client->local->nospoof);
    356 		}
    357 
    358 		/* Copy password to the passwd field if it's given after NICK */
    359 		if ((parc > 2) && (strlen(parv[2]) <= PASSWDLEN))
    360 			safe_strdup(client->local->passwd, parv[2]);
    361 
    362 		/* This had to be copied here to avoid problems.. */
    363 		strlcpy(client->name, nick, sizeof(client->name));
    364 
    365 		/* Let's see if we can get online now... */
    366 		if (is_handshake_finished(client))
    367 		{
    368 			/* Send a CTCP VERSION */
    369 			if (!iConf.ping_cookie && USE_BAN_VERSION && MyConnect(client))
    370 				sendto_one(client, NULL, ":IRC!IRC@%s PRIVMSG %s :\1VERSION\1", me.name, nick);
    371 
    372 			client->lastnick = TStime();
    373 			if (!register_user(client))
    374 			{
    375 				if (IsDead(client))
    376 					return;
    377 				/* ..otherwise.. fallthrough so we run the same code
    378 				 * as in case of !is_handshake_finished()
    379 				 */
    380 			} else {
    381 				/* New user! */
    382 				strlcpy(nick, client->name, sizeof(nick)); /* don't ask, but I need this. do not remove! -- Syzop */
    383 			}
    384 		}
    385 	} else
    386 	if (MyUser(client))
    387 	{
    388 		MessageTag *mtags = NULL;
    389 		int ret;
    390 
    391 		/* Existing client nick-changing */
    392 
    393 		/*
    394 		   ** If the client belongs to me, then check to see
    395 		   ** if client is currently on any channels where it
    396 		   ** is currently banned.  If so, do not allow the nick
    397 		   ** change to occur.
    398 		   ** Also set 'lastnick' to current time, if changed.
    399 		 */
    400 		for (mp = client->user->channel; mp; mp = mp->next)
    401 		{
    402 			int ret = HOOK_CONTINUE;
    403 			Hook *h;
    404 			if (!check_channel_access(client, mp->channel, "hoaq") && is_banned(client, mp->channel, BANCHK_NICK, NULL, NULL))
    405 			{
    406 				sendnumeric(client, ERR_BANNICKCHANGE,
    407 				    mp->channel->name);
    408 				return;
    409 			}
    410 			if (CHECK_TARGET_NICK_BANS && !check_channel_access(client, mp->channel, "hoaq") && is_banned_with_nick(client, mp->channel, BANCHK_NICK, nick, NULL, NULL))
    411 			{
    412 				sendnumeric(client, ERR_BANNICKCHANGE, mp->channel->name);
    413 				return;
    414 			}
    415 
    416 			for (h = Hooks[HOOKTYPE_CHAN_PERMIT_NICK_CHANGE]; h; h = h->next)
    417 			{
    418 				ret = (*(h->func.intfunc))(client,mp->channel);
    419 				if (ret != HOOK_CONTINUE)
    420 					break;
    421 			}
    422 
    423 			if (ret == HOOK_DENY)
    424 			{
    425 				sendnumeric(client, ERR_NONICKCHANGE, mp->channel->name);
    426 				return;
    427 			}
    428 		}
    429 
    430 		unreal_log(ULOG_INFO, "nick", "LOCAL_NICK_CHANGE", client,
    431 		           "Client $client.details has changed their nickname to $new_nick",
    432 		           log_data_string("new_nick", nick));
    433 
    434 		new_message(client, recv_mtags, &mtags);
    435 		RunHook(HOOKTYPE_LOCAL_NICKCHANGE, client, mtags, nick);
    436 		add_history(client, 1, WHOWAS_EVENT_NICK_CHANGE);
    437 		client->lastnick = TStime(); /* needs to be done AFTER add_history() */
    438 		sendto_server(client, 0, 0, mtags, ":%s NICK %s %lld",
    439 		    client->id, nick, (long long)client->lastnick);
    440 		sendto_local_common_channels(client, client, 0, mtags, ":%s NICK :%s", client->name, nick);
    441 		sendto_one(client, mtags, ":%s NICK :%s", client->name, nick);
    442 		free_message_tags(mtags);
    443 		if (removemoder)
    444 			client->umodes &= ~UMODE_REGNICK;
    445 	} else
    446 	{
    447 		/* Someone changing nicks in the pre-registered phase */
    448 	}
    449 
    450 	del_from_client_hash_table(client->name, client);
    451 
    452 	strlcpy(client->name, nick, sizeof(client->name));
    453 	add_to_client_hash_table(nick, client);
    454 
    455 	/* update fdlist --nenolod */
    456 	snprintf(descbuf, sizeof(descbuf), "Client: %s", nick);
    457 	fd_desc(client->local->fd, descbuf);
    458 
    459 	if (removemoder && MyUser(client))
    460 		sendto_one(client, NULL, ":%s MODE %s :-r", me.name, client->name);
    461 
    462 	if (MyUser(client) && !newuser)
    463 		RunHook(HOOKTYPE_POST_LOCAL_NICKCHANGE, client, recv_mtags, oldnick);
    464 }
    465 
    466 /*
    467 ** cmd_uid
    468 **	parv[1] = nickname
    469 **      parv[2] = hopcount
    470 **      parv[3] = timestamp
    471 **      parv[4] = username
    472 **      parv[5] = hostname
    473 **      parv[6] = UID
    474 **	parv[7] = account name (SVID)
    475 **      parv[8] = umodes
    476 **	parv[9] = virthost, * if none
    477 **	parv[10] = cloaked host, * if none
    478 **	parv[11] = ip
    479 **	parv[12] = info
    480 **
    481 ** Technical documentation is available at:
    482 ** https://www.unrealircd.org/docs/Server_protocol:UID_command
    483 */
    484 CMD_FUNC(cmd_uid)
    485 {
    486 	TKL *tklban;
    487 	int ishold;
    488 	Client *acptr, *serv = NULL;
    489 	Client *acptrs;
    490 	char nick[NICKLEN + 1];
    491 	char buf[BUFSIZE];
    492 	long lastnick = 0;
    493 	int differ = 1;
    494 	const char *hostname, *username, *sstamp, *umodes, *virthost, *ip_raw, *realname;
    495 	const char *ip = NULL;
    496 
    497 	if (parc < 13)
    498 	{
    499 		sendnumeric(client, ERR_NEEDMOREPARAMS, "UID");
    500 		return;
    501 	}
    502 
    503 	/* It's not just the directly attached client which must be a
    504 	 * server. The source itself needs to be a server.
    505 	 */
    506 	if (!IsServer(client))
    507 	{
    508 		sendnumeric(client, ERR_NOTFORUSERS, "UID");
    509 		return;
    510 	}
    511 
    512 	strlcpy(nick, parv[1], sizeof(nick));
    513 	hostname = parv[5];
    514 	sstamp = parv[7];
    515 	username = parv[4];
    516 	umodes = parv[8];
    517 	virthost = parv[9];
    518 	ip_raw = parv[11];
    519 	realname = parv[12];
    520 
    521 	/* Do some *MINIMAL* nick name checking for remote nicknames.
    522 	 * This will only catch things that severely break things. -- Syzop
    523 	 */
    524 	if (!do_remote_nick_name(nick) || !strcasecmp("ircd", nick) || !strcasecmp("irc", nick))
    525 	{
    526 		unreal_log(ULOG_ERROR, "nick", "BAD_NICK_REMOTE", client->uplink,
    527 		           "Server link $client tried to introduce bad nick '$nick' -- rejected.",
    528 		           log_data_string("nick", parv[1]));
    529 		sendnumeric(client, ERR_ERRONEUSNICKNAME, parv[1], "Illegal nick name");
    530 
    531 		ircstats.is_kill++;
    532 		/* Send kill to uplink only, hasn't been broadcasted to the rest, anyway */
    533 		sendto_one(client, NULL, ":%s KILL %s :Bad nick", me.id, parv[1]);
    534 		return;
    535 	}
    536 
    537 	if (!valid_uid(parv[6]) || strncmp(parv[6], client->id, 3))
    538 	{
    539 		ircstats.is_kill++;
    540 		unreal_log(ULOG_ERROR, "link", "BAD_UID", client,
    541 		           "Server link $client ($sid) used bad UID $uid in UID command.",
    542 		           log_data_string("sid", client->id),
    543 		           log_data_string("uid", parv[6]));
    544 		/* Send kill to uplink only, hasn't been broadcasted to the rest, anyway */
    545 		sendto_one(client, NULL, ":%s KILL %s :Bad UID", me.id, parv[6]);
    546 		return;
    547 	}
    548 
    549 	if (!valid_host(hostname, 0))
    550 	{
    551 		ircstats.is_kill++;
    552 		unreal_log(ULOG_ERROR, "link", "BAD_HOSTNAME", client,
    553 		           "Server link $client ($client.id) introduced user $nick with bad host name: $bad_hostname.",
    554 		           log_data_string("nick", nick),
    555 		           log_data_string("bad_hostname", hostname));
    556 		/* Send kill to uplink only, hasn't been broadcasted to the rest, anyway */
    557 		sendto_one(client, NULL, ":%s KILL %s :Bad hostname", me.id, parv[6]);
    558 		return;
    559 	}
    560 
    561 	if (strcmp(virthost, "*") && !valid_host(virthost, 0))
    562 	{
    563 		ircstats.is_kill++;
    564 		unreal_log(ULOG_ERROR, "link", "BAD_HOSTNAME", client,
    565 		           "Server link $client ($client.id) introduced user $nick with bad virtual hostname: $bad_hostname.",
    566 		           log_data_string("nick", nick),
    567 		           log_data_string("bad_hostname", virthost));
    568 		/* Send kill to uplink only, hasn't been broadcasted to the rest, anyway */
    569 		sendto_one(client, NULL, ":%s KILL %s :Bad virtual host", me.id, parv[6]);
    570 		return;
    571 	}
    572 
    573 	if (strcmp(ip_raw, "*"))
    574 	{
    575 		if (!(ip = decode_ip(ip_raw)))
    576 		{
    577 			ircstats.is_kill++;
    578 			unreal_log(ULOG_ERROR, "link", "BAD_IP", client,
    579 				   "Server link $client ($client.id) introduced user $nick with bad IP: $bad_ip.",
    580 				   log_data_string("nick", nick),
    581 				   log_data_string("bad_ip", ip_raw));
    582 			/* Send kill to uplink only, hasn't been broadcasted to the rest, anyway */
    583 			sendto_one(client, NULL, ":%s KILL %s :Bad IP in UID command", me.id, parv[6]);
    584 			return;
    585 		}
    586 	}
    587 
    588 	/* Kill quarantined opers early... */
    589 	if (IsQuarantined(client->direction) && strchr(parv[8], 'o'))
    590 	{
    591 		ircstats.is_kill++;
    592 		/* Send kill to uplink only, hasn't been broadcasted to the rest, anyway */
    593 		unreal_log(ULOG_INFO, "link", "OPER_KILLED_QUARANTINE", NULL,
    594 		           "QUARANTINE: Oper $nick on server $server killed, due to quarantine",
    595 		           log_data_string("nick", parv[1]),
    596 		           log_data_client("server", client));
    597 		sendto_one(client, NULL, ":%s KILL %s :Quarantined: no oper privileges allowed", me.id, parv[6]);
    598 		return;
    599 	}
    600 
    601 	if (!IsULine(client) && (tklban = find_qline(client, nick, &ishold)))
    602 	{
    603 		unreal_log(ULOG_INFO, "nick", "QLINE_NICK_REMOTE", client,
    604 			   "Banned nick $nick [$nick.ip] from server $server ($reason)",
    605 			   log_data_string("nick", parv[1]),
    606 			   log_data_string("ip", ip),
    607 			   log_data_client("server", client->uplink),
    608 			   log_data_string("reason", tklban->ptr.nameban->reason));
    609 		/* Let it through */
    610 	}
    611 
    612 	/* Now check if 'nick' already exists - collision with a user (or still in handshake, unknown) */
    613 	if ((acptr = find_client(nick, NULL)) != NULL)
    614 	{
    615 		/* If there's a collision with a user that is still in handshake, on our side,
    616 		 * then we can just kill our client and continue.
    617 		 */
    618 		if (MyConnect(acptr) && IsUnknown(acptr))
    619 		{
    620 			SetKilled(acptr);
    621 			exit_client(acptr, NULL, "Overridden");
    622 			goto nickkill2done;
    623 		}
    624 
    625 		lastnick = atol(parv[3]);
    626 		differ = (mycmp(acptr->user->username, parv[4]) || mycmp(acptr->user->realhost, parv[5]));
    627 
    628 		if (acptr->lastnick == lastnick)
    629 		{
    630 			nick_collision(client, parv[1], parv[6], NULL, acptr, NICKCOL_EQUAL);
    631 			return;	/* We killed both users, now stop the process. */
    632 		}
    633 
    634 		if ((differ && (acptr->lastnick > lastnick)) ||
    635 		    (!differ && (acptr->lastnick < lastnick)) || acptr->direction == client->direction)	/* we missed a QUIT somewhere ? */
    636 		{
    637 			nick_collision(client, parv[1], parv[6], NULL, acptr, NICKCOL_NEW_WON);
    638 			/* We got rid of the "wrong" user. Introduce the correct one. */
    639 			/* ^^ hmm.. why was this absent in nenolod's code, resulting in a 'return 0'? seems wrong. */
    640 			goto nickkill2done;
    641 		}
    642 
    643 		if ((differ && (acptr->lastnick < lastnick)) || (!differ && (acptr->lastnick > lastnick)))
    644 		{
    645 			nick_collision(client, parv[1], parv[6], NULL, acptr, NICKCOL_EXISTING_WON);
    646 			return;	/* Ignore the NICK */
    647 		}
    648 		return; /* just in case */
    649 	}
    650 
    651 nickkill2done:
    652 	/* Proceed with introducing the new client, change source (replace client) */
    653 
    654 	serv = client;
    655 	client = make_client(serv->direction, serv);
    656 	strlcpy(client->id, parv[6], IDLEN);
    657 	add_client_to_list(client);
    658 	add_to_id_hash_table(client->id, client);
    659 	client->lastnick = atol(parv[3]);
    660 	strlcpy(client->name, nick, NICKLEN+1);
    661 	add_to_client_hash_table(nick, client);
    662 
    663 	make_user(client);
    664 
    665 	/* Note that cloaked host aka parv[10] is unused */
    666 
    667 	client->user->server = find_or_add(client->uplink->name);
    668 	strlcpy(client->user->realhost, hostname, sizeof(client->user->realhost));
    669 	if (ip)
    670 		safe_strdup(client->ip, ip);
    671 
    672 	if (*sstamp != '*')
    673 		strlcpy(client->user->account, sstamp, sizeof(client->user->account));
    674 
    675 	strlcpy(client->info, realname, sizeof(client->info));
    676 	strlcpy(client->user->username, username, USERLEN + 1);
    677 	SetUser(client);
    678 
    679 	make_cloakedhost(client, client->user->realhost, client->user->cloakedhost, sizeof(client->user->cloakedhost));
    680 	safe_strdup(client->user->virthost, client->user->cloakedhost);
    681 
    682 	/* Inherit flags from server, makes it easy in the send routines
    683 	 * and this also makes clients inherit ulines.
    684 	 */
    685 	client->flags |= client->uplink->flags;
    686 
    687 	/* Update counts */
    688 	irccounts.clients++;
    689 	if (client->uplink->server)
    690 		client->uplink->server->users++;
    691 	if (client->umodes & UMODE_INVISIBLE)
    692 		irccounts.invisible++;
    693 
    694 	/* Set user modes */
    695 	set_user_modes_dont_spread(client, umodes);
    696 
    697 	/* Set the vhost */
    698 	if (*virthost != '*')
    699 		safe_strdup(client->user->virthost, virthost);
    700 
    701 	build_umode_string(client, 0, SEND_UMODES|UMODE_SERVNOTICE, buf);
    702 
    703 	sendto_serv_butone_nickcmd(client->direction, recv_mtags, client, (*buf == '\0' ? "+" : buf));
    704 
    705 	moddata_extract_s2s_mtags(client, recv_mtags);
    706 
    707 	if (IsLoggedIn(client))
    708 	{
    709 		user_account_login(recv_mtags, client);
    710 		/* no need to check for kill upon user_account_login() here
    711 		 * since that can only happen for local users.
    712 		 */
    713 	}
    714 
    715 	RunHook(HOOKTYPE_REMOTE_CONNECT, client);
    716 
    717 	if (!IsULine(serv) && IsSynched(serv))
    718 	{
    719 		unreal_log(ULOG_INFO, "connect", "REMOTE_CLIENT_CONNECT", client,
    720 			   "Client connecting: $client ($client.user.username@$client.hostname) [$client.ip] $extended_client_info",
    721 			   log_data_string("extended_client_info", get_connect_extinfo(client)),
    722 		           log_data_string("from_server_name", client->user->server));
    723 	}
    724 }
    725 
    726 /** The NICK command.
    727  * In UnrealIRCd 4 and later this should only happen for:
    728  * 1) A local user setting or changing the nick name ("NICK xyz")
    729  *    -> cmd_nick_local()
    730  * 2) A remote user changing their nick name (":<uid> NICK <newnick>")
    731  *    -> cmd_nick_remote()
    732  */
    733 CMD_FUNC(cmd_nick)
    734 {
    735 	if ((parc < 2) || BadPtr(parv[1]))
    736 	{
    737 		sendnumeric(client, ERR_NONICKNAMEGIVEN);
    738 		return;
    739 	}
    740 
    741 	if (MyConnect(client) && !IsServer(client))
    742 	{
    743 		CALL_CMD_FUNC(cmd_nick_local);
    744 	} else
    745 	if (!IsUser(client))
    746 	{
    747 		unreal_log(ULOG_ERROR, "link", "LINK_OLD_PROTOCOL_NICK", client->direction,
    748 		           "Server link $client tried to introduce $nick using NICK command. "
    749 		           "Server is using an old and unsupported protocol from UnrealIRCd 3.2.x or earlier, should use the UID command. "
    750 		           "See https://www.unrealircd.org/docs/FAQ#old-server-protocol",
    751 		           log_data_string("nick", parv[1]));
    752 		/* Split the entire uplink, as it should never have allowed this (and probably they are to blame too) */
    753 		exit_client(client->direction, NULL, "Server used NICK command, bad, must use UID!");
    754 		return;
    755 	} else
    756 	{
    757 		CALL_CMD_FUNC(cmd_nick_remote);
    758 	}
    759 }
    760 
    761 /** Welcome the user on IRC.
    762  * Send the RPL_WELCOME, LUSERS, MOTD, auto join channels, everything...
    763  */
    764 void welcome_user(Client *client, TKL *viruschan_tkl)
    765 {
    766 	int i;
    767 	ConfigItem_tld *tld;
    768 	char buf[BUFSIZE];
    769 
    770 	/* Make creation time the real 'online since' time, excluding registration time.
    771 	 * Otherwise things like set::anti-spam-quit-messagetime 10s could mean
    772 	 * 1 second in practice (#2174).
    773 	 */
    774 	client->local->creationtime = TStime();
    775 	client->local->idle_since = TStime();
    776 
    777 	RunHook(HOOKTYPE_WELCOME, client, 0);
    778 	sendnumeric(client, RPL_WELCOME, NETWORK_NAME, client->name, client->user->username, client->user->realhost);
    779 
    780 	RunHook(HOOKTYPE_WELCOME, client, 1);
    781 	sendnumeric(client, RPL_YOURHOST, me.name, version);
    782 
    783 	RunHook(HOOKTYPE_WELCOME, client, 2);
    784 	sendnumeric(client, RPL_CREATED, creation);
    785 
    786 	RunHook(HOOKTYPE_WELCOME, client, 3);
    787 	sendnumeric(client, RPL_MYINFO, me.name, version, umodestring, cmodestring);
    788 
    789 	RunHook(HOOKTYPE_WELCOME, client, 4);
    790 	for (i = 0; ISupportStrings[i]; i++)
    791 		sendnumeric(client, RPL_ISUPPORT, ISupportStrings[i]);
    792 
    793 	RunHook(HOOKTYPE_WELCOME, client, 5);
    794 
    795 	if (IsHidden(client))
    796 	{
    797 		sendnumeric(client, RPL_HOSTHIDDEN, client->user->virthost);
    798 		RunHook(HOOKTYPE_WELCOME, client, 396);
    799 	}
    800 
    801 	if (IsSecureConnect(client))
    802 	{
    803 		if (client->local->ssl && !iConf.no_connect_tls_info)
    804 		{
    805 			sendnotice(client, "*** You are connected to %s with %s",
    806 				me.name, tls_get_cipher(client));
    807 		}
    808 	}
    809 
    810 	{
    811 		const char *parv[2];
    812 		parv[0] = NULL;
    813 		parv[1] = NULL;
    814 		do_cmd(client, NULL, "LUSERS", 1, parv);
    815 		if (IsDead(client))
    816 			return;
    817 	}
    818 
    819 	RunHook(HOOKTYPE_WELCOME, client, 266);
    820 
    821 	short_motd(client);
    822 
    823 	RunHook(HOOKTYPE_WELCOME, client, 376);
    824 
    825 #ifdef EXPERIMENTAL
    826 	sendnotice(client,
    827 		"*** \2NOTE:\2 This server is running experimental IRC server software (UnrealIRCd %s). "
    828 		"If you find any bugs or problems, please report them at https://bugs.unrealircd.org/",
    829 		VERSIONONLY);
    830 #endif
    831 
    832 	if (client->umodes & UMODE_INVISIBLE)
    833 		irccounts.invisible++;
    834 
    835 	build_umode_string(client, 0, SEND_UMODES|UMODE_SERVNOTICE, buf);
    836 
    837 	sendto_serv_butone_nickcmd(client->direction, NULL, client, (*buf == '\0' ? "+" : buf));
    838 
    839 	broadcast_moddata_client(client);
    840 
    841 	if (buf[0] != '\0' && buf[1] != '\0')
    842 		sendto_one(client, NULL, ":%s MODE %s :%s", client->name,
    843 		    client->name, buf);
    844 
    845 	if (client->user->snomask)
    846 		sendnumeric(client, RPL_SNOMASK, client->user->snomask);
    847 
    848 	if (!IsSecure(client) && !IsLocalhost(client) && (iConf.plaintext_policy_user == POLICY_WARN))
    849 		sendnotice_multiline(client, iConf.plaintext_policy_user_message);
    850 
    851 	if (IsSecure(client) && (iConf.outdated_tls_policy_user == POLICY_WARN) && outdated_tls_client(client))
    852 		sendnotice(client, "%s", outdated_tls_client_build_string(iConf.outdated_tls_policy_user_message, client));
    853 
    854 	RunHook(HOOKTYPE_LOCAL_CONNECT, client);
    855 
    856 	/* Give the user a fresh start as far as fake-lag is concerned.
    857 	 * Otherwise the user could be lagged up already due to all the CAP stuff.
    858 	 */
    859 	client->local->fake_lag = TStime();
    860 
    861 	RunHook(HOOKTYPE_WELCOME, client, 999);
    862 
    863 	/* NOTE: Code after this 'if (viruschan_tkl)' will not be executed for quarantined-
    864 	 *       virus-users. So be carefull with the order. -- Syzop
    865 	 */
    866 	// FIXME: verify if this works, trace code path upstream!!!!
    867 	if (viruschan_tkl)
    868 	{
    869 		join_viruschan(client, viruschan_tkl, SPAMF_USER);
    870 		return;
    871 	}
    872 
    873 	/* Force the user to join the given chans -- codemastr */
    874 	tld = find_tld(client);
    875 
    876 	if (tld && !BadPtr(tld->channel))
    877 	{
    878 		char *chans = strdup(tld->channel);
    879 		const char *args[3] = {
    880 			NULL,
    881 			chans,
    882 			NULL
    883 		};
    884 		do_cmd(client, NULL, "JOIN", 3, args);
    885 		safe_free(chans);
    886 		if (IsDead(client))
    887 			return;
    888 	}
    889 	else if (!BadPtr(AUTO_JOIN_CHANS) && strcmp(AUTO_JOIN_CHANS, "0"))
    890 	{
    891 		char *chans = strdup(AUTO_JOIN_CHANS);
    892 		const char *args[3] = {
    893 			NULL,
    894 			chans,
    895 			NULL
    896 		};
    897 		do_cmd(client, NULL, "JOIN", 3, args);
    898 		safe_free(chans);
    899 		if (IsDead(client))
    900 			return;
    901 	}
    902 }
    903 
    904 /** Make a valid client->user->username, or try to anyway.
    905  * @param client	The client to check
    906  * @param noident	Whether we should ignore the first ~ or not
    907  * @returns 1 if the username is acceptable, 0 if not.
    908  * @note This function will modify client->user->username to make it valid.
    909  *       Only if there are zero valid characters it will return 0.
    910  * @note There is also valid_username() in src/misc.c
    911  */
    912 int make_valid_username(Client *client, int noident)
    913 {
    914 	static char stripuser[USERLEN + 1];
    915 	char *i;
    916 	char *o = stripuser;
    917 	char filtered = 0; /* any changes? */
    918 
    919 	*stripuser = '\0';
    920 
    921 	for (i = client->user->username + noident; *i; i++)
    922 	{
    923 		if (isallowed(*i))
    924 			*o++ = *i;
    925 		else
    926 			filtered = 1;
    927 	}
    928 	*o = '\0';
    929 
    930 	if (filtered == 0)
    931 		return 1; /* No change needed, all good */
    932 
    933 	if (*stripuser == '\0')
    934 		return 0; /* Zero valid characters, reject it */
    935 
    936 	strlcpy(client->user->username + 1, stripuser, sizeof(client->user->username)-1);
    937 	client->user->username[0] = '~';
    938 	client->user->username[USERLEN] = '\0';
    939 	return 1; /* Filtered, but OK */
    940 }
    941 
    942 /** Register the connection as a User - only for local connections!
    943  * This is called after NICK + USER (in no particular order)
    944  * and possibly other protocol messages as well (eg CAP).
    945  * @param client	Client to be made a user.
    946  * @returns 1 if successfully registered, 0 if not (client might be killed).
    947  */
    948 int _register_user(Client *client)
    949 {
    950 	ConfigItem_ban *bconf;
    951 	char *tmpstr;
    952 	char noident = 0;
    953 	int i;
    954 	Hook *h;
    955 	TKL *savetkl = NULL;
    956 	char temp[USERLEN + 1];
    957 	char descbuf[BUFSIZE];
    958 
    959 	if (!MyConnect(client))
    960 		abort();
    961 
    962 	/* Set client->local->sockhost:
    963 	 * First deal with the special 'localhost' case and
    964 	 * then with generic setting based on DNS.
    965 	 */
    966 	if (!strcmp(GetIP(client), "127.0.0.1") ||
    967 	    !strcmp(GetIP(client), "0:0:0:0:0:0:0:1") ||
    968 	    !strcmp(GetIP(client), "0:0:0:0:0:ffff:127.0.0.1"))
    969 	{
    970 		set_sockhost(client, "localhost");
    971 		if (client->local->hostp)
    972 		{
    973 			unreal_free_hostent(client->local->hostp);
    974 			client->local->hostp = NULL;
    975 		}
    976 	} else
    977 	{
    978 		struct hostent *hp = client->local->hostp;
    979 		if (hp && hp->h_name)
    980 			set_sockhost(client, hp->h_name);
    981 	}
    982 
    983 	/* Set the hostname (client->user->realhost).
    984 	 * This may later be overwritten by the AllowClient() call to
    985 	 * revert to the IP again if allow::options::useip is set.
    986 	 */
    987 	strlcpy(client->user->realhost, client->local->sockhost, sizeof(client->local->sockhost));
    988 
    989 	/* Check allow { } blocks... */
    990 	if (!AllowClient(client))
    991 	{
    992 		ircstats.is_ref++;
    993 		/* For safety, we have an extra kill here */
    994 		if (!IsDead(client))
    995 			exit_client(client, NULL, "Rejected");
    996 		return 0;
    997 	}
    998 
    999 	if (IsUseIdent(client))
   1000 	{
   1001 		if (IsIdentSuccess(client))
   1002 		{
   1003 			/* ident succeeded: overwite client->user->username with the ident reply */
   1004 			strlcpy(client->user->username, client->ident, sizeof(client->user->username));
   1005 		} else
   1006 		if (IDENT_CHECK)
   1007 		{
   1008 			/* ident check is enabled and it failed: prefix the username with ~ */
   1009 			char temp[USERLEN+1];
   1010 			strlcpy(temp, client->user->username, sizeof(temp));
   1011 			snprintf(client->user->username, sizeof(client->user->username), "~%s", temp);
   1012 			noident = 1;
   1013 		}
   1014 	}
   1015 
   1016 	/* Now validate the username. This may alter client->user->username
   1017 	 * or reject it completely.
   1018 	 */
   1019 	if (!make_valid_username(client, noident))
   1020 	{
   1021 		exit_client(client, NULL, "Hostile username. Please use only 0-9 a-z A-Z _ - and . in your username.");
   1022 		return 0;
   1023 	}
   1024 
   1025 	/* Check ban realname { } blocks */
   1026 	if ((bconf = find_ban(NULL, client->info, CONF_BAN_REALNAME)))
   1027 	{
   1028 		ircstats.is_ref++;
   1029 		banned_client(client, "realname", bconf->reason?bconf->reason:"", 0, 0);
   1030 		return 0;
   1031 	}
   1032 	/* Check G/Z lines before shuns -- kill before quite -- codemastr */
   1033 	if (find_tkline_match(client, 0))
   1034 	{
   1035 		if (!IsDead(client) && client->local->class)
   1036 		{
   1037 			/* Fix client count bug, in case that it was a hold such as via authprompt */
   1038 			client->local->class->clients--;
   1039 			client->local->class = NULL;
   1040 		}
   1041 		ircstats.is_ref++;
   1042 		return 0;
   1043 	}
   1044 	find_shun(client);
   1045 
   1046 	spamfilter_build_user_string(spamfilter_user, client->name, client);
   1047 	if (match_spamfilter(client, spamfilter_user, SPAMF_USER, NULL, NULL, 0, &savetkl))
   1048 	{
   1049 		if (savetkl && ((savetkl->ptr.spamfilter->action == BAN_ACT_VIRUSCHAN) ||
   1050 				(savetkl->ptr.spamfilter->action == BAN_ACT_SOFT_VIRUSCHAN)))
   1051 		{
   1052 			/* 'viruschan' action:
   1053 			 * Continue with registering the client, and at the end
   1054 			 * of this function we will do the actual joining to the
   1055 			 * virus channel.
   1056 			 */
   1057 		} else {
   1058 			/* Client is either dead or blocked (will hang, on purpose, and timeout) */
   1059 			return 0;
   1060 		}
   1061 	}
   1062 
   1063 	for (h = Hooks[HOOKTYPE_PRE_LOCAL_CONNECT]; h; h = h->next)
   1064 	{
   1065 		int ret = (*(h->func.intfunc))(client);
   1066 		if (ret == HOOK_DENY)
   1067 		{
   1068 			if (!IsDead(client) && client->local->class)
   1069 			{
   1070 				/* Fix client count bug, in case that
   1071 				 * the HOOK_DENY was only meant temporarily.
   1072 				 */
   1073 				client->local->class->clients--;
   1074 				client->local->class = NULL;
   1075 			}
   1076 			return 0;
   1077 		}
   1078 		if (ret == HOOK_ALLOW)
   1079 			break;
   1080 	}
   1081 
   1082 	SetUser(client);
   1083 
   1084 	make_cloakedhost(client, client->user->realhost, client->user->cloakedhost, sizeof(client->user->cloakedhost));
   1085 
   1086 	/* client->user->virthost should never be empty */
   1087 	if (!IsSetHost(client) || !client->user->virthost)
   1088 		safe_strdup(client->user->virthost, client->user->cloakedhost);
   1089 
   1090 	snprintf(descbuf, sizeof descbuf, "Client: %s", client->name);
   1091 	fd_desc(client->local->fd, descbuf);
   1092 
   1093 	/* Move user from unknown list to client list */
   1094 	list_move(&client->lclient_node, &lclient_list);
   1095 
   1096 	/* Update counts */
   1097 	irccounts.unknown--;
   1098 	irccounts.clients++;
   1099 	irccounts.me_clients++;
   1100 	if (client->uplink && client->uplink->server)
   1101 		client->uplink->server->users++;
   1102 
   1103 	if (IsSecure(client))
   1104 	{
   1105 		client->umodes |= UMODE_SECURE;
   1106 		RunHook(HOOKTYPE_SECURE_CONNECT, client);
   1107 	}
   1108 
   1109 	safe_free(client->local->passwd);
   1110 
   1111 	unreal_log(ULOG_INFO, "connect", "LOCAL_CLIENT_CONNECT", client,
   1112 		   "Client connecting: $client ($client.user.username@$client.hostname) [$client.ip] $extended_client_info",
   1113 		   log_data_string("extended_client_info", get_connect_extinfo(client)));
   1114 
   1115 	/* Send the RPL_WELCOME, LUSERS, MOTD, auto join channels, everything... */
   1116 	welcome_user(client, savetkl);
   1117 
   1118 	return IsDead(client) ? 0 : 1;
   1119 }
   1120 
   1121 /** Nick collission detected. A winner has been decided upstream. Deal with killing.
   1122  * I moved this all to a single routine here rather than having all code duplicated
   1123  * due to SID vs NICK and some code quadruplicated.
   1124  */
   1125 void nick_collision(Client *cptr, const char *newnick, const char *newid, Client *new, Client *existing, int type)
   1126 {
   1127 	char comment[512];
   1128 	const char *new_server, *existing_server;
   1129 	const char *who_won;
   1130 	const char *nickcol_reason;
   1131 
   1132 	if (type == NICKCOL_NEW_WON)
   1133 		who_won = "new";
   1134 	else if (type == NICKCOL_EXISTING_WON)
   1135 		who_won = "existing";
   1136 	else
   1137 		who_won = "none";
   1138 
   1139 	nickcol_reason = new ? "nick change" : "new user connecting";
   1140 
   1141 	unreal_log(ULOG_ERROR, "nick", "NICK_COLLISION", NULL,
   1142 	           "Nick collision: "
   1143 	           "$new_nick[$new_id]@$uplink (new) vs "
   1144 	           "$existing_client[$existing_client.id]@$existing_client.user.servername (existing). "
   1145 	           "Winner: $nick_collision_winner. "
   1146 	           "Cause: $nick_collision_reason",
   1147 	           log_data_string("new_nick", newnick),
   1148 	           log_data_string("new_id", newid),
   1149 	           log_data_client("uplink", cptr),
   1150 	           log_data_client("existing_client", existing),
   1151 	           log_data_string("nick_collision_winner", who_won),
   1152 	           log_data_string("nick_collision_reason", nickcol_reason));
   1153 
   1154 	new_server = cptr->name;
   1155 	existing_server = (existing == existing->direction) ? me.name : existing->direction->name;
   1156 	if (type == NICKCOL_EXISTING_WON)
   1157 		snprintf(comment, sizeof(comment), "Nick collision: %s <- %s", new_server, existing_server);
   1158 	else if (type == NICKCOL_NEW_WON)
   1159 		snprintf(comment, sizeof(comment), "Nick collision: %s <- %s", existing_server, new_server);
   1160 	else
   1161 		snprintf(comment, sizeof(comment), "Nick collision: %s <-> %s", existing_server, new_server);
   1162 
   1163 	/* We only care about the direction from this point, not about the originally sending server */
   1164 	cptr = cptr->direction;
   1165 
   1166 	if ((type == NICKCOL_EQUAL) || (type == NICKCOL_EXISTING_WON))
   1167 	{
   1168 		/* Kill 'new':
   1169 		 * - 'new' is known by the cptr-side as 'newnick' already
   1170 		 * - if not nick-changing then the other servers don't know this user
   1171 		 * - if nick-changing, then the the other servers know the user as new->name
   1172 		 */
   1173 
   1174 		/* cptr case first... this side knows the user by newnick/newid */
   1175 		/* SID server can kill 'new' by ID */
   1176 		sendto_one(cptr, NULL, ":%s KILL %s :%s", me.id, newid, comment);
   1177 
   1178 		/* non-cptr case... only necessary if nick-changing. */
   1179 		if (new)
   1180 		{
   1181 			MessageTag *mtags = NULL;
   1182 
   1183 			new_message(new, NULL, &mtags);
   1184 
   1185 			/* non-cptr side knows this user by their old nick name */
   1186 			sendto_server(cptr, 0, 0, mtags, ":%s KILL %s :%s", me.id, new->id, comment);
   1187 
   1188 			/* Exit the client */
   1189 			ircstats.is_kill++;
   1190 			SetKilled(new);
   1191 			exit_client(new, mtags, comment);
   1192 
   1193 			free_message_tags(mtags);
   1194 		}
   1195 	}
   1196 
   1197 	if ((type == NICKCOL_EQUAL) || (type == NICKCOL_NEW_WON))
   1198 	{
   1199 		MessageTag *mtags = NULL;
   1200 
   1201 		new_message(existing, NULL, &mtags);
   1202 
   1203 		/* Now let's kill 'existing' */
   1204 		sendto_server(NULL, 0, 0, mtags, ":%s KILL %s :%s", me.id, existing->id, comment);
   1205 
   1206 		/* Exit the client */
   1207 		ircstats.is_kill++;
   1208 		SetKilled(existing);
   1209 		exit_client(existing, mtags, comment);
   1210 
   1211 		free_message_tags(mtags);
   1212 	}
   1213 }
   1214 
   1215 /** Returns 1 if allow::maxperip is exceeded by 'client' */
   1216 int exceeds_maxperip(Client *client, ConfigItem_allow *aconf)
   1217 {
   1218 	Client *acptr;
   1219 	int local_cnt = 1;
   1220 	int global_cnt = 1;
   1221 
   1222 	if (find_tkl_exception(TKL_MAXPERIP, client))
   1223 		return 0; /* exempt */
   1224 
   1225 	list_for_each_entry(acptr, &client_list, client_node)
   1226 	{
   1227 		if (IsUser(acptr) && !strcmp(GetIP(acptr), GetIP(client)))
   1228 		{
   1229 			if (MyUser(acptr))
   1230 			{
   1231 				local_cnt++;
   1232 				if (local_cnt > aconf->maxperip)
   1233 					return 1;
   1234 			}
   1235 			global_cnt++;
   1236 			if (global_cnt > aconf->global_maxperip)
   1237 				return 1;
   1238 		}
   1239 	}
   1240 	return 0;
   1241 }
   1242 
   1243 /** Allow or reject the client based on allow { } blocks and all other restrictions.
   1244  * @param client     Client to check (local)
   1245  * @param username   Username, for some reason...
   1246  * @returns 1 if OK, 0 if client is rejected (likely killed too)
   1247  */
   1248 int AllowClient(Client *client)
   1249 {
   1250 	static char sockhost[HOSTLEN + 1];
   1251 	int i;
   1252 	ConfigItem_allow *aconf;
   1253 	char *hname;
   1254 	static char uhost[HOSTLEN + USERLEN + 3];
   1255 	static char fullname[HOSTLEN + 1];
   1256 
   1257 	if (!IsSecure(client) && !IsLocalhost(client) && (iConf.plaintext_policy_user == POLICY_DENY))
   1258 	{
   1259 		exit_client(client, NULL, iConf.plaintext_policy_user_message->line);
   1260 		return 0;
   1261 	}
   1262 
   1263 	if (IsSecure(client) && (iConf.outdated_tls_policy_user == POLICY_DENY) && outdated_tls_client(client))
   1264 	{
   1265 		const char *msg = outdated_tls_client_build_string(iConf.outdated_tls_policy_user_message, client);
   1266 		exit_client(client, NULL, msg);
   1267 		return 0;
   1268 	}
   1269 
   1270 	for (aconf = conf_allow; aconf; aconf = aconf->next)
   1271 	{
   1272 		if (aconf->flags.tls && !IsSecure(client))
   1273 			continue;
   1274 
   1275 		if (!user_allowed_by_security_group(client, aconf->match))
   1276 			continue;
   1277 
   1278 		/* Check authentication */
   1279 		if (aconf->auth && !Auth_Check(client, aconf->auth, client->local->passwd))
   1280 		{
   1281 			/* Incorrect password/authentication - but was is it required? */
   1282 			if (aconf->flags.reject_on_auth_failure)
   1283 			{
   1284 				exit_client(client, NULL, iConf.reject_message_unauthorized);
   1285 				return 0;
   1286 			} else {
   1287 				continue; /* Continue (this is the default behavior) */
   1288 			}
   1289 		}
   1290 
   1291 		if (!aconf->flags.noident)
   1292 			SetUseIdent(client);
   1293 
   1294 		if (aconf->flags.useip)
   1295 			set_sockhost(client, GetIP(client));
   1296 
   1297 		if (exceeds_maxperip(client, aconf))
   1298 		{
   1299 			/* Already got too many with that ip# */
   1300 			exit_client(client, NULL, iConf.reject_message_too_many_connections);
   1301 			return 0;
   1302 		}
   1303 
   1304 		if (!((aconf->class->clients + 1) > aconf->class->maxclients))
   1305 		{
   1306 			client->local->class = aconf->class;
   1307 			client->local->class->clients++;
   1308 		}
   1309 		else
   1310 		{
   1311 			/* Class is full */
   1312 			sendnumeric(client, RPL_REDIR, aconf->server ? aconf->server : DEFAULT_SERVER, aconf->port ? aconf->port : 6667);
   1313 			exit_client(client, NULL, iConf.reject_message_server_full);
   1314 			return 0;
   1315 		}
   1316 		return 1;
   1317 	}
   1318 	/* User did not match any allow { } blocks: */
   1319 	exit_client(client, NULL, iConf.reject_message_unauthorized);
   1320 	return 0;
   1321 }