unrealircd

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

issecure.c (9530B)

      1 /*
      2  * Channel Is Secure UnrealIRCd module (Channel Mode +Z)
      3  * (C) Copyright 2010-.. Bram Matthys (Syzop) and the UnrealIRCd team
      4  *
      5  * This module will indicate if a channel is secure, and if so will set +Z.
      6  * Secure is defined as: all users on the channel are connected through TLS
      7  * Additionally, the channel has to be +z (only allow secure users to join).
      8  * Suggested on http://bugs.unrealircd.org/view.php?id=3720
      9  * Thanks go to fez for pushing us for some kind of method to indicate
     10  * this 'secure channel state', and to Stealth for suggesting this method.
     11  *
     12  * This program is free software; you can redistribute it and/or modify
     13  * it under the terms of the GNU General Public License as published by
     14  * the Free Software Foundation; either version 1, or (at your option)
     15  * any later version.
     16  *
     17  * This program is distributed in the hope that it will be useful,
     18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     20  * GNU General Public License for more details.
     21  *
     22  * You should have received a copy of the GNU General Public License
     23  * along with this program; if not, write to the Free Software
     24  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     25  */
     26 
     27 #include "unrealircd.h"
     28 
     29 CMD_FUNC(issecure);
     30 
     31 ModuleHeader MOD_HEADER
     32   = {
     33 	"chanmodes/issecure",
     34 	"4.2",
     35 	"Channel Mode +Z", 
     36 	"UnrealIRCd Team",
     37 	"unrealircd-6",
     38     };
     39 
     40 Cmode_t EXTCMODE_ISSECURE;
     41 
     42 #define IsSecureChanIndicated(channel)	(channel->mode.mode & EXTCMODE_ISSECURE)
     43 
     44 int IsSecureJoin(Channel *channel);
     45 int modeZ_is_ok(Client *client, Channel *channel, char mode, const char *para, int checkt, int what);
     46 int issecure_join(Client *client, Channel *channel, MessageTag *mtags);
     47 int issecure_part(Client *client, Channel *channel, MessageTag *mtags, const char *comment);
     48 int issecure_quit(Client *client, MessageTag *mtags, const char *comment);
     49 int issecure_kick(Client *client, Client *victim, Channel *channel, MessageTag *mtags, const char *comment);
     50 int issecure_chanmode(Client *client, Channel *channel, MessageTag *mtags,
     51                              const char *modebuf, const char *parabuf, time_t sendts, int samode, int *destroy_channel);
     52                              
     53 
     54 MOD_TEST()
     55 {
     56 	return MOD_SUCCESS;
     57 }
     58 
     59 MOD_INIT()
     60 {
     61 CmodeInfo req;
     62 
     63 	/* Channel mode */
     64 	memset(&req, 0, sizeof(req));
     65 	req.paracount = 0;
     66 	req.is_ok = modeZ_is_ok;
     67 	req.letter = 'Z';
     68 	req.local = 1; /* local channel mode */
     69 	CmodeAdd(modinfo->handle, req, &EXTCMODE_ISSECURE);
     70 	
     71 	HookAdd(modinfo->handle, HOOKTYPE_LOCAL_JOIN, 0, issecure_join);
     72 	HookAdd(modinfo->handle, HOOKTYPE_REMOTE_JOIN, 0, issecure_join);
     73 	HookAdd(modinfo->handle, HOOKTYPE_LOCAL_PART, 0, issecure_part);
     74 	HookAdd(modinfo->handle, HOOKTYPE_REMOTE_PART, 0, issecure_part);
     75 	HookAdd(modinfo->handle, HOOKTYPE_LOCAL_QUIT, 0, issecure_quit);
     76 	HookAdd(modinfo->handle, HOOKTYPE_REMOTE_QUIT, 0, issecure_quit);
     77 	HookAdd(modinfo->handle, HOOKTYPE_LOCAL_KICK, 0, issecure_kick);
     78 	HookAdd(modinfo->handle, HOOKTYPE_REMOTE_KICK, 0, issecure_kick);
     79 	HookAdd(modinfo->handle, HOOKTYPE_LOCAL_CHANMODE, 0, issecure_chanmode);
     80 	HookAdd(modinfo->handle, HOOKTYPE_REMOTE_CHANMODE, 0, issecure_chanmode);
     81 	
     82 	MARK_AS_OFFICIAL_MODULE(modinfo);
     83 	return MOD_SUCCESS;
     84 }
     85 
     86 MOD_LOAD()
     87 {
     88 	return MOD_SUCCESS;
     89 }
     90 
     91 MOD_UNLOAD()
     92 {
     93 	return MOD_SUCCESS;
     94 }
     95 
     96 int IsSecureJoin(Channel *channel)
     97 {
     98 	Hook *h;
     99 	int i = 0;
    100 
    101 	for (h = Hooks[HOOKTYPE_IS_CHANNEL_SECURE]; h; h = h->next)
    102 	{
    103 		i = (*(h->func.intfunc))(channel);
    104 		if (i != 0)
    105 			break;
    106 	}
    107 
    108 	return i;
    109 }
    110 
    111 int modeZ_is_ok(Client *client, Channel *channel, char mode, const char *para, int checkt, int what)
    112 {
    113 	/* Reject any attempt to set or unset our mode. Even to IRCOps */
    114 	return EX_ALWAYS_DENY;
    115 }
    116 
    117 int channel_has_insecure_users_butone(Channel *channel, Client *skip)
    118 {
    119 Member *member;
    120 
    121 	for (member = channel->members; member; member = member->next)
    122 	{
    123 		if (member->client == skip)
    124 			continue;
    125 		if (IsULine(member->client))
    126 			continue;
    127 		if (!IsSecureConnect(member->client))
    128 			return 1;
    129 	}
    130 	return 0;
    131 }
    132 
    133 #define channel_has_insecure_users(x) channel_has_insecure_users_butone(x, NULL)
    134 
    135 /* Set channel status of 'channel' to be no longer secure (-Z) due to 'client'.
    136  * client MAY be null!
    137  */
    138 void issecure_unset(Channel *channel, Client *client, MessageTag *recv_mtags, int notice)
    139 {
    140 	Hook *h;
    141 	MessageTag *mtags;
    142 
    143 	if (notice)
    144 	{
    145 		mtags = NULL;
    146 		new_message_special(&me, recv_mtags, &mtags, "NOTICE %s :setting -Z", channel->name);
    147 		sendto_channel(channel, &me, NULL, 0, 0, SEND_LOCAL, mtags,
    148 		               ":%s NOTICE %s :User '%s' joined and is not connected through TLS, setting channel -Z (insecure)",
    149 		               me.id, channel->name, client->name);
    150 		free_message_tags(mtags);
    151 	}
    152 		
    153 	channel->mode.mode &= ~EXTCMODE_ISSECURE;
    154 	mtags = NULL;
    155 	new_message_special(&me, recv_mtags, &mtags, "MODE %s -Z", channel->name);
    156 	sendto_channel(channel, &me, NULL, 0, 0, SEND_LOCAL, mtags, ":%s MODE %s -Z", me.name, channel->name);
    157 	free_message_tags(mtags);
    158 }
    159 
    160 
    161 /* Set channel status of 'channel' to be secure (+Z).
    162  * Channel might have been insecure (or might not have been +z) and is
    163  * now considered secure. If 'client' is non-NULL then we are now secure
    164  * thanks to this user leaving the chat.
    165  */
    166 void issecure_set(Channel *channel, Client *client, MessageTag *recv_mtags, int notice)
    167 {
    168 	MessageTag *mtags;
    169 
    170 	mtags = NULL;
    171 	new_message_special(&me, recv_mtags, &mtags, "NOTICE %s :setting +Z", channel->name);
    172 	if (notice && client)
    173 	{
    174 		/* note that we have to skip 'client', since when this call is being made
    175 		 * he is still considered a member of this channel.
    176 		 */
    177 		sendto_channel(channel, &me, client, 0, 0, SEND_LOCAL, NULL,
    178 		               ":%s NOTICE %s :Now all users in the channel are connected through TLS, setting channel +Z (secure)",
    179 		               me.name, channel->name);
    180 	} else if (notice)
    181 	{
    182 		/* note the missing word 'now' in next line */
    183 		sendto_channel(channel, &me, NULL, 0, 0, SEND_LOCAL, NULL,
    184 		               ":%s NOTICE %s :All users in the channel are connected through TLS, setting channel +Z (secure)",
    185 		               me.name, channel->name);
    186 	}
    187 	free_message_tags(mtags);
    188 
    189 	channel->mode.mode |= EXTCMODE_ISSECURE;
    190 
    191 	mtags = NULL;
    192 	new_message_special(&me, recv_mtags, &mtags, "MODE %s +Z", channel->name);
    193 	sendto_channel(channel, &me, client, 0, 0, SEND_LOCAL, mtags,
    194 	               ":%s MODE %s +Z",
    195 	               me.name, channel->name);
    196 	free_message_tags(mtags);
    197 }
    198 
    199 /* Note: the routines below (notably the 'if's) are written with speed in mind,
    200  *       so while they can be written shorter, they would only take longer to execute!
    201  */
    202 
    203 int issecure_join(Client *client, Channel *channel, MessageTag *mtags)
    204 {
    205 	/* Check only if chan already +zZ and the user joining is insecure (no need to count) */
    206 	if (IsSecureJoin(channel) && IsSecureChanIndicated(channel) && !IsSecureConnect(client) && !IsULine(client))
    207 		issecure_unset(channel, client, mtags, 1);
    208 
    209 	/* Special case for +z in modes-on-join and first user creating the channel */
    210 	if ((channel->users == 1) && IsSecureJoin(channel) && !IsSecureChanIndicated(channel) && !channel_has_insecure_users(channel))
    211 		issecure_set(channel, NULL, mtags, 0);
    212 
    213 	return 0;
    214 }
    215 
    216 int issecure_part(Client *client, Channel *channel, MessageTag *mtags, const char *comment)
    217 {
    218 	/* Only care if chan is +z-Z and the user leaving is insecure, then count */
    219 	if (IsSecureJoin(channel) && !IsSecureChanIndicated(channel) && !IsSecureConnect(client) &&
    220 	    !channel_has_insecure_users_butone(channel, client))
    221 		issecure_set(channel, client, mtags, 1);
    222 	return 0;
    223 }
    224 
    225 int issecure_quit(Client *client, MessageTag *mtags, const char *comment)
    226 {
    227 Membership *membership;
    228 Channel *channel;
    229 
    230 	for (membership = client->user->channel; membership; membership=membership->next)
    231 	{
    232 		channel = membership->channel;
    233 		/* Identical to part */
    234 		if (IsSecureJoin(channel) && !IsSecureChanIndicated(channel) && 
    235 		    !IsSecureConnect(client) && !channel_has_insecure_users_butone(channel, client))
    236 			issecure_set(channel, client, mtags, 1);
    237 	}
    238 	return 0;
    239 }
    240 
    241 int issecure_kick(Client *client, Client *victim, Channel *channel, MessageTag *mtags, const char *comment)
    242 {
    243 	/* Identical to part&quit, except we care about 'victim' and not 'client' */
    244 	if (IsSecureJoin(channel) && !IsSecureChanIndicated(channel) &&
    245 	    !IsSecureConnect(victim) && !channel_has_insecure_users_butone(channel, victim))
    246 		issecure_set(channel, victim, mtags, 1);
    247 	return 0;
    248 }
    249 
    250 int issecure_chanmode(Client *client, Channel *channel, MessageTag *mtags,
    251                              const char *modebuf, const char *parabuf, time_t sendts, int samode, int *destroy_channel)
    252 {
    253 	if (!strchr(modebuf, 'z'))
    254 		return 0; /* don't care */
    255 
    256 	if (IsSecureJoin(channel))
    257 	{
    258 		/* +z is set, check if we need to +Z
    259 		 * Note that we need to be careful as there is a possibility that we got here
    260 		 * but the channel is ALREADY +z. Due to server2server MODE's.
    261 		 */
    262 		if (channel_has_insecure_users(channel))
    263 		{
    264 			/* Should be -Z, if not already */
    265 			if (IsSecureChanIndicated(channel))
    266 				issecure_unset(channel, NULL, mtags, 0); /* would be odd if we got here ;) */
    267 		} else {
    268 			/* Should be +Z, but check if it isn't already.. */
    269 			if (!IsSecureChanIndicated(channel))
    270 				issecure_set(channel, NULL, mtags, 0);
    271 		}
    272 	} else {
    273 		/* there was a -z, check if the channel is currently +Z and if so, set it -Z */
    274 		if (IsSecureChanIndicated(channel))
    275 			issecure_unset(channel, NULL, mtags, 0);
    276 	}
    277 	return 0;
    278 }