unrealircd

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

message-ids.c (4885B)

      1 /*
      2  *   IRC - Internet Relay Chat, src/modules/message-ids.c
      3  *   (C) 2019 Syzop & 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 	"message-ids",
     28 	"5.0",
     29 	"msgid CAP",
     30 	"UnrealIRCd Team",
     31 	"unrealircd-6",
     32 	};
     33 
     34 /* Variables */
     35 long CAP_ACCOUNT_TAG = 0L;
     36 
     37 int msgid_mtag_is_ok(Client *client, const char *name, const char *value);
     38 void mtag_add_or_inherit_msgid(Client *sender, MessageTag *recv_mtags, MessageTag **mtag_list, const char *signature);
     39 
     40 MOD_INIT()
     41 {
     42 	MessageTagHandlerInfo mtag;
     43 
     44 	MARK_AS_OFFICIAL_MODULE(modinfo);
     45 
     46 	memset(&mtag, 0, sizeof(mtag));
     47 	mtag.name = "msgid";
     48 	mtag.is_ok = msgid_mtag_is_ok;
     49 	mtag.flags = MTAG_HANDLER_FLAGS_NO_CAP_NEEDED;
     50 	MessageTagHandlerAdd(modinfo->handle, &mtag);
     51 
     52 	HookAddVoid(modinfo->handle, HOOKTYPE_NEW_MESSAGE, 0, mtag_add_or_inherit_msgid);
     53 
     54 	return MOD_SUCCESS;
     55 }
     56 
     57 MOD_LOAD()
     58 {
     59 	return MOD_SUCCESS;
     60 }
     61 
     62 MOD_UNLOAD()
     63 {
     64 	return MOD_SUCCESS;
     65 }
     66 
     67 /** This function verifies if the client sending
     68  * 'msgid' is permitted to do so and uses a permitted
     69  * syntax.
     70  * We simply allow msgid ONLY from servers and with any syntax.
     71  */
     72 int msgid_mtag_is_ok(Client *client, const char *name, const char *value)
     73 {
     74 	if (IsServer(client) && !BadPtr(value))
     75 		return 1;
     76 
     77 	return 0;
     78 }
     79 
     80 /** Generate a msgid.
     81  * @returns a MessageTag struct that you can use directly.
     82  * @note
     83  * Apparently there has been some discussion on what method to use to
     84  * generate msgid's. I am not going to list them here. Just saying that
     85  * they have been considered and we chose to go for a string that contains
     86  * 128+ bits of randomness, which has an extremely low chance of colissions.
     87  * Or, to quote wikipedia on the birthday attack problem:
     88  * "For comparison, 10^-18 to 10^-15 is the uncorrectable bit error rate
     89  *  of a typical hard disk. In theory, hashes or UUIDs being 128 bits,
     90  *  should stay within that range until about 820 billion outputs"
     91  * For reference, 10^-15 is 0.000000000000001%
     92  * The main reasons for this choice are: that it is extremely simple,
     93  * the chance of making a mistake in an otherwise complex implementation
     94  * is nullified and we don't risk "leaking" any details.
     95  */
     96 MessageTag *mtag_generate_msgid(void)
     97 {
     98 	MessageTag *m = safe_alloc(sizeof(MessageTag));
     99 	safe_strdup(m->name, "msgid");
    100 	m->value = safe_alloc(MSGIDLEN+1);
    101 	gen_random_alnum(m->value, MSGIDLEN);
    102 	return m;
    103 }
    104 
    105 
    106 void mtag_add_or_inherit_msgid(Client *sender, MessageTag *recv_mtags, MessageTag **mtag_list, const char *signature)
    107 {
    108 	MessageTag *m = find_mtag(recv_mtags, "msgid");
    109 	if (m)
    110 		m = duplicate_mtag(m);
    111 	else
    112 		m = mtag_generate_msgid();
    113 
    114 	if (signature)
    115 	{
    116 		/* Special case:
    117 		 * Some commands will receive a single msgid from
    118 		 * a remote server for multiple events.
    119 		 * Take for example SJOIN which may contain 5 joins,
    120 		 * 3 bans setting, 2 invites, and setting a few modes.
    121 		 * This way we can still generate unique msgid's
    122 		 * for such sub-events. It is a hash of the subevent
    123 		 * concatenated to the existing msgid.
    124 		 * The hash is the first half of a SHA256 hash, then
    125 		 * base64'd, and with the == suffix removed.
    126 		 */
    127 		char prefix[MSGIDLEN+1], *p;
    128 		strlcpy(prefix, m->value, sizeof(prefix));
    129 		p = strchr(prefix, '-');
    130 		if (p)
    131 		{
    132 			/* It is possible that we have more stacking.
    133 			 * IOTW: we are already stacked like xxx-yyy
    134 			 * and it would have become an xxx-yyy-zzz
    135 			 * sequence. Instead, we strip the yyy-
    136 			 * so the end result will be xxx-zzz.
    137 			 *
    138 			 * One example code path would be when someone joins
    139 			 * and the issecure module sets -Z.
    140 			 */
    141 			*p = '\0';
    142 		}
    143 		SHA256_CTX hash;
    144 		char binaryhash[SHA256_DIGEST_LENGTH];
    145 		char b64hash[SHA256_DIGEST_LENGTH*2+1];
    146 		char newbuf[256];
    147 		memset(&binaryhash, 0, sizeof(binaryhash));
    148 		memset(&b64hash, 0, sizeof(b64hash));
    149 		sha256hash_binary(binaryhash, signature, strlen(signature));
    150 		b64_encode(binaryhash, sizeof(binaryhash)/2, b64hash, sizeof(b64hash));
    151 		b64hash[22] = '\0'; /* cut off at '=' */
    152 		snprintf(newbuf, sizeof(newbuf), "%s-%s", prefix, b64hash);
    153 		safe_strdup(m->value, newbuf);
    154 	}
    155 	AddListItem(m, *mtag_list);
    156 }