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 }