unrealircd

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

user.c (26152B)

      1 /*
      2  *   Unreal Internet Relay Chat Daemon, src/user.c
      3  *   Copyright (C) 1990 Jarkko Oikarinen and
      4  *                      University of Oulu, Computing Center
      5  *
      6  *   See file AUTHORS in IRC package for additional names of
      7  *   the programmers.
      8  *
      9  *   This program is free software; you can redistribute it and/or modify
     10  *   it under the terms of the GNU General Public License as published by
     11  *   the Free Software Foundation; either version 1, or (at your option)
     12  *   any later version.
     13  *
     14  *   This program is distributed in the hope that it will be useful,
     15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17  *   GNU General Public License for more details.
     18  *
     19  *   You should have received a copy of the GNU General Public License
     20  *   along with this program; if not, write to the Free Software
     21  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     22  */
     23 
     24 /** @file
     25  * @brief User-related functions
     26  */
     27 
     28 /* s_user.c 2.74 2/8/94 (C) 1988 University of Oulu, Computing Center and Jarkko Oikarinen */
     29 
     30 #include "unrealircd.h"
     31 
     32 MODVAR int dontspread = 0;
     33 
     34 /** Inhibit labeled/response reply. This means it will result in an empty ACK
     35  *  because we cannot handle the command via labeled-reponse. Rare, but
     36  *  possible in for example /TRACE which multiple servers handle and which
     37  *  has no clear end.
     38  */
     39 MODVAR int labeled_response_inhibit = 0;
     40 
     41 /** Force a labeled/response reply (of course, only if a label is present etc.).
     42  * This is used in case the "a remote server is handling the request" was
     43  * incorrect and there were 0 responses. This is the case for PRIVMSG.
     44  * It will force an empty ACK.
     45  * No, this cannot be merged with the other one. Also, the other one
     46  * (labeled_response_inhibit) has priority over this one (labeled_response_force).
     47  */
     48 MODVAR int labeled_response_force = 0;
     49 
     50 /** Inhibit labeled/response END. Only used in /LIST.
     51  */
     52 MODVAR int labeled_response_inhibit_end = 0;
     53 
     54 /** Set to 1 if an UTF8 incompatible nick character set is in use */
     55 MODVAR int non_utf8_nick_chars_in_use = 0;
     56 
     57 /** Set a new vhost on the user
     58  * @param client	The client (user)
     59  * @param host		The new vhost
     60  */
     61 void iNAH_host(Client *client, const char *host)
     62 {
     63 	if (!client->user)
     64 		return;
     65 
     66 	userhost_save_current(client);
     67 
     68 	safe_strdup(client->user->virthost, host);
     69 	if (MyConnect(client))
     70 		sendto_server(NULL, 0, 0, NULL, ":%s SETHOST :%s", client->id, client->user->virthost);
     71 	client->umodes |= UMODE_SETHOST|UMODE_HIDE;
     72 
     73 	userhost_changed(client);
     74 }
     75 
     76 /** Convert a user mode string to a bitmask - only used by config.
     77  * @param umode		The user mode string
     78  * @returns the user mode value (long)
     79  */
     80 long set_usermode(const char *umode)
     81 {
     82 	Umode *um;
     83 	int newumode;
     84 	int what;
     85 	const char *m;
     86 
     87 	newumode = 0;
     88 	what = MODE_ADD;
     89 	for (m = umode; *m; m++)
     90 	{
     91 		switch (*m)
     92 		{
     93 			case '+':
     94 				what = MODE_ADD;
     95 				break;
     96 			case '-':
     97 				what = MODE_DEL;
     98 				break;
     99 			case ' ':
    100 			case '\n':
    101 			case '\r':
    102 			case '\t':
    103 				break;
    104 			default:
    105 				for (um = usermodes; um; um = um->next)
    106 				{
    107 					if (um->letter == *m)
    108 					{
    109 						if (what == MODE_ADD)
    110 							newumode |= um->mode;
    111 						else
    112 							newumode &= ~um->mode;
    113 					}
    114 				}
    115 		}
    116 	}
    117 
    118 	return newumode;
    119 }
    120 
    121 /** Convert a target pointer to an 8 bit hash, used for target limiting. */
    122 unsigned char hash_target(void *target)
    123 {
    124 	uintptr_t v = (uintptr_t)target;
    125 	/* ircu does >> 16 and 8 but since our sizeof(Client) is
    126 	 * towards 512 (and hence the alignment), that bit is useless.
    127 	 * So we do >> 17 and 9.
    128 	 */
    129 	return (unsigned char)((v >> 17) ^ (v >> 9));
    130 }
    131 
    132 /** target_limit_exceeded
    133  * @param client   The client.
    134  * @param target The target client
    135  * @param name   The name of the target client (used in the error message)
    136  * @retval Returns 1 if too many targets were addressed (do not send!), 0 if ok to send.
    137  */
    138 int target_limit_exceeded(Client *client, void *target, const char *name)
    139 {
    140 	u_char hash = hash_target(target);
    141 	int i;
    142 	int max_concurrent_conversations_users, max_concurrent_conversations_new_user_every;
    143 	FloodSettings *settings;
    144 
    145 	if (ValidatePermissionsForPath("immune:max-concurrent-conversations",client,NULL,NULL,NULL))
    146 		return 0;
    147 
    148 	if (client->local->targets[0] == hash)
    149 		return 0;
    150 
    151 	settings = get_floodsettings_for_user(client, FLD_CONVERSATIONS);
    152 	max_concurrent_conversations_users = settings->limit[FLD_CONVERSATIONS];
    153 	max_concurrent_conversations_new_user_every = settings->period[FLD_CONVERSATIONS];
    154 
    155 	if (max_concurrent_conversations_users <= 0)
    156 		return 0; /* unlimited */
    157 
    158 	/* Shouldn't be needed, but better check here than access out-of-bounds memory */
    159 	if (max_concurrent_conversations_users > MAXCCUSERS)
    160 		max_concurrent_conversations_users = MAXCCUSERS;
    161 
    162 	for (i = 1; i < max_concurrent_conversations_users; i++)
    163 	{
    164 		if (client->local->targets[i] == hash)
    165 		{
    166 			/* Move this target hash to the first position */
    167 			memmove(&client->local->targets[1], &client->local->targets[0], i);
    168 			client->local->targets[0] = hash;
    169 			return 0;
    170 		}
    171 	}
    172 
    173 	if (TStime() < client->local->nexttarget)
    174 	{
    175 		/* Target limit reached */
    176 		client->local->nexttarget += 2; /* punish them some more */
    177 		add_fake_lag(client, 2000); /* lag them up as well */
    178 
    179 		flood_limit_exceeded_log(client, "max-concurrent-conversations");
    180 		sendnumeric(client, ERR_TARGETTOOFAST, name, (long long)(client->local->nexttarget - TStime()));
    181 
    182 		return 1;
    183 	}
    184 
    185 	/* If not set yet or in the very past, then adjust it.
    186 	 * This is so client->local->nexttarget=0 will become client->local->nexttarget=currenttime-...
    187 	 */
    188 	if (TStime() > client->local->nexttarget +
    189 	    (max_concurrent_conversations_users * max_concurrent_conversations_new_user_every))
    190 	{
    191 		client->local->nexttarget = TStime() - ((max_concurrent_conversations_users-1) * max_concurrent_conversations_new_user_every);
    192 	}
    193 
    194 	client->local->nexttarget += max_concurrent_conversations_new_user_every;
    195 
    196 	/* Add the new target (first move the rest, then add us at position 0 */
    197 	memmove(&client->local->targets[1], &client->local->targets[0], max_concurrent_conversations_users - 1);
    198 	client->local->targets[0] = hash;
    199 
    200 	return 0;
    201 }
    202 
    203 /** De-duplicate a string of "x,x,y,z" to "x,y,z"
    204  * @param buffer	Input string
    205  * @returns The new de-duplicated buffer (temporary storage, only valid until next canonize call)
    206  */
    207 char *canonize(const char *buffer)
    208 {
    209 	static char cbuf[2048];
    210 	char tbuf[2048];
    211 	char *s, *t, *cp = cbuf;
    212 	int  l = 0;
    213 	char *p = NULL, *p2;
    214 
    215 	*cp = '\0';
    216 
    217 	if (!buffer)
    218 		return NULL;
    219 
    220 	strlcpy(tbuf, buffer, sizeof(tbuf));
    221 	for (s = strtoken(&p, tbuf, ","); s; s = strtoken(&p, NULL, ","))
    222 	{
    223 		if (l)
    224 		{
    225 			for (p2 = NULL, t = strtoken(&p2, cbuf, ","); t;
    226 			    t = strtoken(&p2, NULL, ","))
    227 				if (!mycmp(s, t))
    228 					break;
    229 				else if (p2)
    230 					p2[-1] = ',';
    231 		}
    232 		else
    233 			t = NULL;
    234 		if (!t)
    235 		{
    236 			if (l)
    237 				*(cp - 1) = ',';
    238 			else
    239 				l = 1;
    240 			strcpy(cp, s);
    241 			if (p)
    242 				cp += (p - s);
    243 		}
    244 		else if (p2)
    245 			p2[-1] = ',';
    246 	}
    247 	return cbuf;
    248 }
    249 
    250 /** Get user modes as a string.
    251  * @param client	The client
    252  * @returns string of user modes (temporary storage)
    253  */
    254 const char *get_usermode_string(Client *client)
    255 {
    256 	static char buf[128];
    257 	Umode *um;
    258 
    259 	strlcpy(buf, "+", sizeof(buf));
    260 	for (um = usermodes; um; um = um->next)
    261 		if (client->umodes & um->mode)
    262 			strlcat_letter(buf, um->letter, sizeof(buf));
    263 
    264 	return buf;
    265 }
    266 
    267 /** Get user modes as a string - buffer is specified.
    268  * @param client	The client
    269  * @param buf		The buffer to write to
    270  * @param buflen	The size of the buffer
    271  * @returns string of user modes (buf)
    272  */
    273 const char *get_usermode_string_r(Client *client, char *buf, size_t buflen)
    274 {
    275 	Umode *um;
    276 
    277 	strlcpy(buf, "+", buflen);
    278 	for (um = usermodes; um; um = um->next)
    279 		if (client->umodes & um->mode)
    280 			strlcat_letter(buf, um->letter, buflen);
    281 
    282 	return buf;
    283 }
    284 
    285 /** Get user modes as a string - this one does not work on 'client' but directly on 'umodes'.
    286  * @param umodes	The user modes that are set
    287  * @returns string of user modes (temporary storage)
    288  */
    289 const char *get_usermode_string_raw(long umodes)
    290 {
    291 	static char buf[128];
    292 	Umode *um;
    293 
    294 	strlcpy(buf, "+", sizeof(buf));
    295 	for (um = usermodes; um; um = um->next)
    296 		if (umodes & um->mode)
    297 			strlcat_letter(buf, um->letter, sizeof(buf));
    298 
    299 	return buf;
    300 }
    301 
    302 /** Get user modes as a string - this one does not work on 'client' but directly on 'umodes'.
    303  * @param umodes	The user modes that are set
    304  * @param buf		The buffer to write to
    305  * @param buflen	The size of the buffer
    306  * @returns string of user modes (buf)
    307  */
    308 const char *get_usermode_string_raw_r(long umodes, char *buf, size_t buflen)
    309 {
    310 	Umode *um;
    311 
    312 	strlcpy(buf, "+", buflen);
    313 	for (um = usermodes; um; um = um->next)
    314 		if (umodes & um->mode)
    315 			strlcat_letter(buf, um->letter, buflen);
    316 
    317 	return buf;
    318 }
    319 
    320 
    321 /** Set a new snomask on the user.
    322  * The user is not informed of the change by this function.
    323  * @param client	The client
    324  * @param snomask	The snomask to add or delete (eg: "+k-c")
    325  */
    326 void set_snomask(Client *client, const char *snomask)
    327 {
    328 	int what = MODE_ADD; /* keep this an int. -- Syzop */
    329 	const char *p;
    330 	int i;
    331 
    332 	if (snomask == NULL)
    333 	{
    334 		remove_all_snomasks(client);
    335 		return;
    336 	}
    337 	
    338 	for (p = snomask; p && *p; p++)
    339 	{
    340 		switch (*p)
    341 		{
    342 			case '+':
    343 				what = MODE_ADD;
    344 				break;
    345 			case '-':
    346 				what = MODE_DEL;
    347 				break;
    348 			default:
    349 				if (what == MODE_ADD)
    350 				{
    351 					if (!isalpha(*p) || !is_valid_snomask(*p))
    352 						continue;
    353 					addlettertodynamicstringsorted(&client->user->snomask, *p);
    354 				} else {
    355 					delletterfromstring(client->user->snomask, *p);
    356 				}
    357 				break;
    358 		}
    359 	}
    360 	/* If the snomask becomes empty ("") then set it to NULL and user mode -s */
    361 	if (client->user->snomask && !*client->user->snomask)
    362 		remove_all_snomasks(client);
    363 }
    364 
    365 /** Build the MODE line with (modified) user modes for this user.
    366  * @author Originally by avalon.
    367  */
    368 void build_umode_string(Client *client, long old, long sendmask, char *umode_buf)
    369 {
    370 	Umode *um;
    371 	long flag;
    372 	char *m;
    373 	int what = MODE_NULL;
    374 
    375 	/*
    376 	 * build a string in umode_buf to represent the change in the user's
    377 	 * mode between the new (client->flag) and 'old'.
    378 	 */
    379 	m = umode_buf;
    380 	*m = '\0';
    381 	for (um = usermodes; um; um = um->next)
    382 	{
    383 		flag = um->mode;
    384 		if (MyUser(client) && !(flag & sendmask))
    385 			continue;
    386 		if ((flag & old) && !(client->umodes & flag))
    387 		{
    388 			if (what == MODE_DEL)
    389 				*m++ = um->letter;
    390 			else
    391 			{
    392 				what = MODE_DEL;
    393 				*m++ = '-';
    394 				*m++ = um->letter;
    395 			}
    396 		}
    397 		else if (!(flag & old) && (client->umodes & flag))
    398 		{
    399 			if (what == MODE_ADD)
    400 				*m++ = um->letter;
    401 			else
    402 			{
    403 				what = MODE_ADD;
    404 				*m++ = '+';
    405 				*m++ = um->letter;
    406 			}
    407 		}
    408 	}
    409 	*m = '\0';
    410 }
    411 
    412 /** Send usermode change to other servers.
    413  * @param client	The client
    414  * @param show_to_user	Set to 1 to show the MODE change to the user
    415  * @param old		The old user modes set on the client
    416  */
    417 void send_umode_out(Client *client, int show_to_user, long old)
    418 {
    419 	Client *acptr;
    420 	char buf[512];
    421 
    422 	build_umode_string(client, old, SEND_UMODES, buf);
    423 
    424 	list_for_each_entry(acptr, &server_list, special_node)
    425 	{
    426 		if ((acptr != client) && (acptr != client->direction) && *buf)
    427 		{
    428 			sendto_one(acptr, NULL, ":%s UMODE2 %s",
    429 			           client->name, buf);
    430 		}
    431 	}
    432 
    433 	if (MyUser(client) && show_to_user)
    434 	{
    435 		build_umode_string(client, old, ALL_UMODES, buf);
    436 		if (*buf)
    437 			sendto_one(client, NULL, ":%s MODE %s :%s", client->name, client->name, buf);
    438 	}
    439 }
    440 
    441 static MaxTarget *maxtargets = NULL; /**< For set::max-targets-per-command configuration */
    442 
    443 static void maxtarget_add_sorted(MaxTarget *n)
    444 {
    445 	MaxTarget *e;
    446 
    447 	if (!maxtargets)
    448 	{
    449 		maxtargets = n;
    450 		return;
    451 	}
    452 
    453 	for (e = maxtargets; e; e = e->next)
    454 	{
    455 		if (strcmp(n->cmd, e->cmd) < 0)
    456 		{
    457 			/* Insert us before */
    458 			if (e->prev)
    459 				e->prev->next = n;
    460 			else
    461 				maxtargets = n; /* new head */
    462 			n->prev = e->prev;
    463 
    464 			n->next = e;
    465 			e->prev = n;
    466 			return;
    467 		}
    468 		if (!e->next)
    469 		{
    470 			/* Append us at end */
    471 			e->next = n;
    472 			n->prev = e;
    473 			return;
    474 		}
    475 	}
    476 }
    477 
    478 /** Find a maxtarget structure for a cmd (internal) */
    479 MaxTarget *findmaxtarget(const char *cmd)
    480 {
    481 	MaxTarget *m;
    482 
    483 	for (m = maxtargets; m; m = m->next)
    484 		if (!strcasecmp(m->cmd, cmd))
    485 			return m;
    486 	return NULL;
    487 }
    488 
    489 /** Set a maximum targets per command restriction */
    490 void setmaxtargets(const char *cmd, int limit)
    491 {
    492 	MaxTarget *m = findmaxtarget(cmd);
    493 	if (!m)
    494 	{
    495 		char cmdupper[64];
    496 		strlcpy(cmdupper, cmd, sizeof(cmdupper));
    497 		strtoupper(cmdupper);
    498 		m = safe_alloc(sizeof(MaxTarget));
    499 		safe_strdup(m->cmd, cmdupper);
    500 		maxtarget_add_sorted(m);
    501 	}
    502 	m->limit = limit;
    503 }
    504 
    505 /** Free all set::max-targets-per-command configuration (internal) */
    506 void freemaxtargets(void)
    507 {
    508 	MaxTarget *m, *m_next;
    509 
    510 	for (m = maxtargets; m; m = m_next)
    511 	{
    512 		m_next = m->next;
    513 		safe_free(m->cmd);
    514 		safe_free(m);
    515 	}
    516 	maxtargets = NULL;
    517 }
    518 
    519 /** Return the maximum number of targets permitted for a command */
    520 int max_targets_for_command(const char *cmd)
    521 {
    522 	MaxTarget *m = findmaxtarget(cmd);
    523 	if (m)
    524 		return m->limit;
    525 	return 1; /* default to 1 */
    526 }
    527 
    528 void set_isupport_targmax(void)
    529 {
    530 	char buf[512], tbuf[64];
    531 	MaxTarget *m;
    532 
    533 	*buf = '\0';
    534 	for (m = maxtargets; m; m = m->next)
    535 	{
    536 		if (m->limit == MAXTARGETS_MAX)
    537 			snprintf(tbuf, sizeof(tbuf), "%s:", m->cmd);
    538 		else
    539 			snprintf(tbuf, sizeof(tbuf), "%s:%d", m->cmd, m->limit);
    540 
    541 		if (*buf)
    542 			strlcat(buf, ",", sizeof(buf));
    543 		strlcat(buf, tbuf, sizeof(buf));
    544 	}
    545 	ISupportSet(NULL, "TARGMAX", buf);
    546 }
    547 
    548 /** Called between config test and config run */
    549 void set_targmax_defaults(void)
    550 {
    551 	/* Free existing... */
    552 	freemaxtargets();
    553 
    554 	/* Set the defaults */
    555 	setmaxtargets("PRIVMSG", 4);
    556 	setmaxtargets("NOTICE", 1);
    557 	setmaxtargets("TAGMSG", 1);
    558 	setmaxtargets("NAMES", 1); // >1 is not supported
    559 	setmaxtargets("WHOIS", 1);
    560 	setmaxtargets("WHOWAS", 1); // >1 is not supported
    561 	setmaxtargets("KICK", 4);
    562 	setmaxtargets("LIST", MAXTARGETS_MAX);
    563 	setmaxtargets("JOIN", MAXTARGETS_MAX);
    564 	setmaxtargets("PART", MAXTARGETS_MAX);
    565 	setmaxtargets("SAJOIN", MAXTARGETS_MAX);
    566 	setmaxtargets("SAPART", MAXTARGETS_MAX);
    567 	setmaxtargets("KILL", MAXTARGETS_MAX);
    568 	setmaxtargets("DCCALLOW", MAXTARGETS_MAX);
    569 	/* The following 3 are space-separated (and actually the previous
    570 	 * mentioned DCCALLOW is both space-and-comma separated).
    571 	 * It seems most IRCd's don't list space-separated targets list
    572 	 * in TARGMAX... On the other hand, why not? It says nowhere in
    573 	 * the TARGMAX specification that it's only for comma-separated
    574 	 * commands. So let's be nice and consistent and inform the
    575 	 * clients about the limits for such commands as well:
    576 	 */
    577 	setmaxtargets("USERHOST", MAXTARGETS_MAX); // not configurable
    578 	setmaxtargets("USERIP", MAXTARGETS_MAX); // not configurable
    579 	setmaxtargets("ISON", MAXTARGETS_MAX); // not configurable
    580 	setmaxtargets("WATCH", MAXTARGETS_MAX); // not configurable
    581 }
    582 
    583 /** Is the user handshake finished and can register_user() be called?
    584  * This checks things like: do we have a NICK, USER, nospoof,
    585  * and any other things modules may add:
    586  * eg: the cap module checks if client capability negotiation
    587  * is in progress
    588  */
    589 int is_handshake_finished(Client *client)
    590 {
    591 	Hook *h;
    592 	int n;
    593 
    594 	for (h = Hooks[HOOKTYPE_IS_HANDSHAKE_FINISHED]; h; h = h->next)
    595 	{
    596 		n = (*(h->func.intfunc))(client);
    597 		if (n == 0)
    598 			return 0; /* We can stop already */
    599 	}
    600 
    601 	/* I figured these can be here, in the core: */
    602 	if (client->user && *client->user->username && client->name[0] && IsNotSpoof(client))
    603 		return 1;
    604 
    605 	return 0;
    606 }
    607 
    608 /** Should we show connection info to the user?
    609  * This depends on the set::show-connect-info setting but also
    610  * on various other properties, such as serversonly ports,
    611  * websocket, etc.
    612  * If someone needs it, then we can also call a hook here. Just tell us.
    613  */
    614 int should_show_connect_info(Client *client)
    615 {
    616 	if (SHOWCONNECTINFO &&
    617 	    !client->server &&
    618 	    !IsServersOnlyListener(client->local->listener) &&
    619 	    !client->local->listener->websocket_options)
    620 	{
    621 		return 1;
    622 	}
    623 	return 0;
    624 }
    625 
    626 /* (helper function for uid_get) */
    627 static char uid_int_to_char(int v)
    628 {
    629 	if (v < 10)
    630 		return '0'+v;
    631 	else
    632 		return 'A'+v-10;
    633 }
    634 
    635 /** Acquire a new unique UID */
    636 const char *uid_get(void)
    637 {
    638 	Client *acptr;
    639 	static char uid[IDLEN];
    640 	static int uidcounter = 0;
    641 
    642 	uidcounter++;
    643 	if (uidcounter == 36*36)
    644 		uidcounter = 0;
    645 
    646 	do
    647 	{
    648 		snprintf(uid, sizeof(uid), "%s%c%c%c%c%c%c",
    649 			me.id,
    650 			uid_int_to_char(getrandom8() % 36),
    651 			uid_int_to_char(getrandom8() % 36),
    652 			uid_int_to_char(getrandom8() % 36),
    653 			uid_int_to_char(getrandom8() % 36),
    654 			uid_int_to_char(uidcounter / 36),
    655 			uid_int_to_char(uidcounter % 36));
    656 		acptr = find_client(uid, NULL);
    657 	} while (acptr);
    658 
    659 	return uid;
    660 }
    661 
    662 /** Get cloaked host for user */
    663 const char *getcloak(Client *client)
    664 {
    665 	if (!*client->user->cloakedhost)
    666 	{
    667 		/* need to calculate (first-time) */
    668 		make_cloakedhost(client, client->user->realhost, client->user->cloakedhost, sizeof(client->user->cloakedhost));
    669 	}
    670 
    671 	return client->user->cloakedhost;
    672 }
    673 
    674 /** Calculate the cloaked host for a client.
    675  * @param client	The client
    676  * @param curr		The real host or real IP
    677  * @param buf		Buffer to store the new cloaked host in
    678  * @param buflen	Length of the buffer (should be HOSTLEN+1)
    679  */
    680 void make_cloakedhost(Client *client, const char *curr, char *buf, size_t buflen)
    681 {
    682 	const char *p;
    683 	char host[256], *q;
    684 	const char *mask;
    685 
    686 	/* Convert host to lowercase and cut off at 255 bytes just to be sure */
    687 	for (p = curr, q = host; *p && (q < host+sizeof(host)-1); p++, q++)
    688 		*q =  tolower(*p);
    689 	*q = '\0';
    690 
    691 	/* Call the cloaking layer */
    692 	if (RCallbacks[CALLBACKTYPE_CLOAK_EX] != NULL)
    693 		mask = RCallbacks[CALLBACKTYPE_CLOAK_EX]->func.stringfunc(client, host);
    694 	else if (RCallbacks[CALLBACKTYPE_CLOAK] != NULL)
    695 		mask = RCallbacks[CALLBACKTYPE_CLOAK]->func.stringfunc(host);
    696 	else
    697 		mask = curr;
    698 
    699 	strlcpy(buf, mask, buflen);
    700 }
    701 
    702 /** Called after a user is logged in (or out) of a services account */
    703 void user_account_login(MessageTag *recv_mtags, Client *client)
    704 {
    705 	if (MyConnect(client))
    706 	{
    707 		find_shun(client);
    708 		if (find_tkline_match(client, 0) && IsDead(client))
    709 			return;
    710 	}
    711 	RunHook(HOOKTYPE_ACCOUNT_LOGIN, client, recv_mtags);
    712 }
    713 
    714 /** Should we hide the idle time of 'target' to user 'client'?
    715  * This depends on the set::hide-idle-time policy.
    716  */
    717 int hide_idle_time(Client *client, Client *target)
    718 {
    719 	/* First of all, IRCOps bypass the restriction */
    720 	if (IsOper(client))
    721 		return 0;
    722 
    723 	/* Other than that, it depends on the settings: */
    724 	switch (iConf.hide_idle_time)
    725 	{
    726 		case HIDE_IDLE_TIME_NEVER:
    727 			return 0;
    728 		case HIDE_IDLE_TIME_ALWAYS:
    729 			return 1;
    730 		case HIDE_IDLE_TIME_USERMODE:
    731 		case HIDE_IDLE_TIME_OPER_USERMODE:
    732 			if (target->umodes & UMODE_HIDLE)
    733 				return 1;
    734 			return 0;
    735 		default:
    736 			return 0;
    737 	}
    738 }
    739 
    740 /** Get creation time of a client.
    741  * @param client	The client to check (user, server, anything)
    742  * @returns the time when the client first connected to IRC, or 0 for unknown.
    743  */
    744 time_t get_creationtime(Client *client)
    745 {
    746 	const char *str;
    747 
    748 	/* Shortcut for local clients */
    749 	if (client->local)
    750 		return client->local->creationtime;
    751 
    752 	/* Otherwise, hopefully available through this... */
    753 	str = moddata_client_get(client, "creationtime");
    754 	if (!BadPtr(str) && (*str != '0'))
    755 		return atoll(str);
    756 	return 0;
    757 }
    758 
    759 /** Get how long a client is connected to IRC.
    760  * @param client	The client to check
    761  * @returns how long the client is connected to IRC (number of seconds)
    762  */
    763 long get_connected_time(Client *client)
    764 {
    765 	const char *str;
    766 	long connect_time = 0;
    767 
    768 	/* Shortcut for local clients */
    769 	if (client->local)
    770 		return TStime() - client->local->creationtime;
    771 
    772 	/* Otherwise, hopefully available through this... */
    773 	str = moddata_client_get(client, "creationtime");
    774 	if (!BadPtr(str) && (*str != '0'))
    775 		return TStime() - atoll(str);
    776 	return 0;
    777 }
    778 
    779 /** Return extended information about user for the "Client connecting" line.
    780  * @returns A string such as "[secure] [reputation: 5]", never returns NULL.
    781  */
    782 const char *get_connect_extinfo(Client *client)
    783 {
    784 	static char retbuf[512];
    785 	char tmp[512];
    786 	const char *s;
    787 	const char *secgroups;
    788 	NameValuePrioList *list = NULL, *e;
    789 
    790 	/* From modules... */
    791 	RunHook(HOOKTYPE_CONNECT_EXTINFO, client, &list);
    792 
    793 	/* And some built-in: */
    794 
    795 	/* "vhost": this should be first */
    796 	if (IsHidden(client))
    797 		add_nvplist(&list, -1000000, "vhost", client->user->virthost);
    798 
    799 	/* "class": second */
    800 	if (MyUser(client) && client->local->class)
    801 		add_nvplist(&list, -100000, "class", client->local->class->name);
    802 
    803 	/* "secure": TLS */
    804 	s = tls_get_cipher(client);
    805 	if (s)
    806 		add_nvplist(&list, -1000, "secure", s);
    807 	else if (IsSecure(client) || IsSecureConnect(client))
    808 		add_nvplist(&list, -1000, "secure", NULL); /* old server or otherwise no details (eg: fake secure) */
    809 
    810 	/* services account? */
    811 	if (IsLoggedIn(client))
    812 		add_nvplist(&list, -500, "account", client->user->account);
    813 
    814 	/* security groups */
    815 	secgroups = get_security_groups(client);
    816 	if (secgroups)
    817 		add_nvplist(&list, 100, "security-groups", secgroups);
    818 	
    819 	/* tkl shunned */
    820 	if (IsShunned(client))
    821 		add_nvplist(&list, 110, "shunned", NULL);
    822 
    823 	*retbuf = '\0';
    824 	for (e = list; e; e = e->next)
    825 	{
    826 		if (e->value)
    827 			snprintf(tmp, sizeof(tmp), "[%s: %s] ", e->name, e->value);
    828 		else
    829 			snprintf(tmp, sizeof(tmp), "[%s] ", e->name);
    830 		strlcat(retbuf, tmp, sizeof(retbuf));
    831 	}
    832 	/* Cut off last space (unless empty string) */
    833 	if (*retbuf)
    834 		retbuf[strlen(retbuf)-1] = '\0';
    835 
    836 	/* Free the list, as it was only used to build retbuf */
    837 	free_nvplist(list);
    838 
    839 	return retbuf;
    840 }
    841 
    842 /** Log a message that flood protection kicked in for the client.
    843  * This sends to the +f snomask at the moment.
    844  * @param client	The client to check flood for (local user)
    845  * @param opt		The flood option (eg FLD_AWAY)
    846  */
    847 void flood_limit_exceeded_log(Client *client, const char *floodname)
    848 {
    849 	char buf[1024];
    850 
    851 	// NOTE: If you ever change this format, there are a few more
    852 	// direct unreal_log() calls with "FLOOD_BLOCKED" in the file
    853 	// src/modules/targetfloodprot.c, so update those as well.
    854 	unreal_log(ULOG_INFO, "flood", "FLOOD_BLOCKED", client,
    855 	           "Flood blocked ($flood_type) from $client.details [$client.ip]",
    856 	           log_data_string("flood_type", floodname));
    857 }
    858 
    859 /** Is the flood limit exceeded for an option? eg for away-flood.
    860  * @param client	The client to check flood for (local user)
    861  * @param opt		The flood option (eg FLD_AWAY)
    862  * @note This increments the flood counter as well.
    863  * @returns 1 if exceeded, 0 if not.
    864  */
    865 int flood_limit_exceeded(Client *client, FloodOption opt)
    866 {
    867 	FloodSettings *f;
    868 
    869 	if (!MyUser(client))
    870 		return 0;
    871 
    872 	f = get_floodsettings_for_user(client, opt);
    873 	if (f->limit[opt] <= 0)
    874 		return 0; /* No limit set or unlimited */
    875 
    876 	/* Ok, let's do the flood check */
    877 	if ((client->local->flood[opt].t + f->period[opt]) <= timeofday)
    878 	{
    879 		/* Time exceeded, reset */
    880 		client->local->flood[opt].count = 0;
    881 		client->local->flood[opt].t = timeofday;
    882 	}
    883 	if (client->local->flood[opt].count <= f->limit[opt])
    884 		client->local->flood[opt].count++;
    885 	if (client->local->flood[opt].count > f->limit[opt])
    886 	{
    887 		flood_limit_exceeded_log(client, floodoption_names[opt]);
    888 		return 1; /* Flood limit hit! */
    889 	}
    890 
    891 	return 0;
    892 }
    893 
    894 /** Get the appropriate anti-flood settings block for this user.
    895  * @param client	The client, should be locally connected.
    896  * @param opt		The flood option we are interested in
    897  * @returns The FloodSettings for this user, never returns NULL.
    898  */
    899 FloodSettings *get_floodsettings_for_user(Client *client, FloodOption opt)
    900 {
    901 	SecurityGroup *s;
    902 	FloodSettings *f;
    903 
    904 	/* Go through all security groups by order of priority
    905 	 * (eg: first "known-users", then "unknown-users").
    906 	 * For each of these:
    907 	 * - Check if a set::anti-flood::xxxx block exists for this group
    908 	 * - Check if the limit is non-zero (eg there is any limit set)
    909 	 * If any of these are false then we continue with next block
    910 	 * that matches.
    911 	 */
    912 
    913 	// XXX: alternatively, instead of this double loop,
    914 	//      do a post-conf thing and sort iConf.floodsettings
    915 	//      according to the security-group { } order.
    916 	for (s = securitygroups; s; s = s->next)
    917 	{
    918 		if (user_allowed_by_security_group(client, s) &&
    919 		    ((f = find_floodsettings_block(s->name))) &&
    920 		    f->limit[opt])
    921 		{
    922 			return f;
    923 		}
    924 	}
    925 
    926 	/* Return default settings block (which may have a zero limit set) */
    927 	f = find_floodsettings_block("unknown-users");
    928 	if (!f)
    929 		abort(); /* impossible */
    930 
    931 	return f;
    932 }
    933 
    934 MODVAR const char *floodoption_names[] = {
    935 	"nick-flood",
    936 	"join-flood",
    937 	"away-flood",
    938 	"invite-flood",
    939 	"knock-flood",
    940 	"max-concurrent-conversations",
    941 	"lag-penalty",
    942 	"vhost-flood",
    943 	NULL
    944 };
    945 
    946 /** Lookup GEO information for an IP address.
    947  * @param ip	The IP to lookup
    948  * @returns A struct containing all the details. Must be freed by caller!
    949  */
    950 GeoIPResult *geoip_lookup(const char *ip)
    951 {
    952 	if (!RCallbacks[CALLBACKTYPE_GEOIP_LOOKUP])
    953 		return NULL;
    954 	return RCallbacks[CALLBACKTYPE_GEOIP_LOOKUP]->func.pvoidfunc(ip);
    955 }
    956 
    957 void free_geoip_result(GeoIPResult *r)
    958 {
    959 	if (!r)
    960 		return;
    961 	safe_free(r->country_code);
    962 	safe_free(r->country_name);
    963 	safe_free(r);
    964 }
    965 
    966 /** Grab geoip information for client */
    967 GeoIPResult *geoip_client(Client *client)
    968 {
    969 	ModData *m = moddata_client_get_raw(client, "geoip");
    970 	if (!m)
    971 		return NULL;
    972 	return m->ptr; /* can still be NULL */
    973 }
    974 
    975 /** Get the oper block that was used to become OPER.
    976  * @param client	The client to fetch the info for
    977  * @returns the oper block name (eg: "OpEr") or NULL.
    978  */
    979 const char *get_operlogin(Client *client)
    980 {
    981 	if (client->user->operlogin)
    982 		return client->user->operlogin;
    983 	return moddata_client_get(client, "operlogin");
    984 }
    985 
    986 /** Get the operclass of the IRCOp.
    987  * @param client	The client to fetch the info for
    988  * @returns the operclass name or NULL
    989  */
    990 const char *get_operclass(Client *client)
    991 {
    992 	const char *operlogin = NULL;
    993 
    994 	if (MyUser(client) && client->user->operlogin)
    995 	{
    996 		ConfigItem_oper *oper;
    997 		operlogin = client->user->operlogin;
    998 		oper = find_oper(operlogin);
    999 		if (oper && oper->operclass)
   1000 			return oper->operclass;
   1001 	}
   1002 
   1003 	/* Remote user or locally no longer available
   1004 	 * (eg oper block removed but user is still oper)
   1005 	 */
   1006 	return moddata_client_get(client, "operclass");
   1007 }