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 SSL/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 "config.h"
28 #include "struct.h"
29 #include "common.h"
30 #include "sys.h"
31 #include "numeric.h"
32 #include "msg.h"
33 #include "proto.h"
34 #include "channel.h"
35 #include <time.h>
36 #include <sys/stat.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #ifdef _WIN32
41 #include <io.h>
42 #endif
43 #include <fcntl.h>
44 #include "h.h"
45 #ifdef STRIPBADWORDS
46 #include "badwords.h"
47 #endif
48 #ifdef _WIN32
49 #include "version.h"
50 #endif
51
52 DLLFUNC CMD_FUNC(m_issecure);
53
54 ModuleHeader MOD_HEADER(m_issecure)
55 = {
56 "m_issecure",
57 "$Id$",
58 "Channel Mode +Z",
59 "3.2-b8-1",
60 NULL
61 };
62
63 Cmode_t EXTCMODE_ISSECURE;
64
65 #define IsSecureJoin(chptr) (chptr->mode.mode & MODE_ONLYSECURE)
66 #define IsSecureChanIndicated(chptr) (chptr->mode.extmode & EXTCMODE_ISSECURE)
67
68
69 int modeZ_is_ok(aClient *sptr, aChannel *chptr, char *para, int checkt, int what);
70 DLLFUNC int issecure_join(aClient *cptr, aClient *sptr, aChannel *chptr, char *parv[]);
71 DLLFUNC int issecure_part(aClient *cptr, aClient *sptr, aChannel *chptr, char *comment);
72 DLLFUNC int issecure_quit(aClient *acptr, char *comment);
73 DLLFUNC int issecure_kick(aClient *cptr, aClient *sptr, aClient *acptr, aChannel *chptr, char *comment);
74 DLLFUNC int issecure_chanmode(aClient *cptr, aClient *sptr, aChannel *chptr,
75 char *modebuf, char *parabuf, int sendts, int samode);
76
77
MOD_TEST(m_issecure)78 DLLFUNC int MOD_TEST(m_issecure)(ModuleInfo *modinfo)
79 {
80 return MOD_SUCCESS;
81 }
82
MOD_INIT(m_issecure)83 DLLFUNC int MOD_INIT(m_issecure)(ModuleInfo *modinfo)
84 {
85 CmodeInfo req;
86
87 /* Channel mode */
88 memset(&req, 0, sizeof(req));
89 req.paracount = 0;
90 req.is_ok = modeZ_is_ok;
91 req.flag = 'Z';
92 req.local = 1; /* local channel mode */
93 CmodeAdd(modinfo->handle, req, &EXTCMODE_ISSECURE);
94
95 HookAddEx(modinfo->handle, HOOKTYPE_LOCAL_JOIN, issecure_join);
96 HookAddEx(modinfo->handle, HOOKTYPE_REMOTE_JOIN, issecure_join);
97 HookAddEx(modinfo->handle, HOOKTYPE_LOCAL_PART, issecure_part);
98 HookAddEx(modinfo->handle, HOOKTYPE_REMOTE_PART, issecure_part);
99 HookAddEx(modinfo->handle, HOOKTYPE_LOCAL_QUIT, issecure_quit);
100 HookAddEx(modinfo->handle, HOOKTYPE_REMOTE_QUIT, issecure_quit);
101 HookAddEx(modinfo->handle, HOOKTYPE_LOCAL_KICK, issecure_kick);
102 HookAddEx(modinfo->handle, HOOKTYPE_REMOTE_KICK, issecure_kick);
103 HookAddEx(modinfo->handle, HOOKTYPE_LOCAL_CHANMODE, issecure_chanmode);
104 HookAddEx(modinfo->handle, HOOKTYPE_REMOTE_CHANMODE, issecure_chanmode);
105
106 MARK_AS_OFFICIAL_MODULE(modinfo);
107 return MOD_SUCCESS;
108 }
109
MOD_LOAD(m_issecure)110 DLLFUNC int MOD_LOAD(m_issecure)(int module_load)
111 {
112 return MOD_SUCCESS;
113 }
114
MOD_UNLOAD(m_issecure)115 DLLFUNC int MOD_UNLOAD(m_issecure)(int module_unload)
116 {
117 return MOD_SUCCESS;
118 }
119
modeZ_is_ok(aClient * sptr,aChannel * chptr,char * para,int checkt,int what)120 int modeZ_is_ok(aClient *sptr, aChannel *chptr, char *para, int checkt, int what)
121 {
122 /* Reject any attempt to set or unset our mode. Even to IRCOps */
123 return EX_ALWAYS_DENY;
124 }
125
channel_has_insecure_users_butone(aChannel * chptr,aClient * skip)126 int channel_has_insecure_users_butone(aChannel *chptr, aClient *skip)
127 {
128 Member *member;
129
130 for (member = chptr->members; member; member = member->next)
131 {
132 if (member->cptr == skip)
133 continue;
134 if (IsULine(member->cptr))
135 continue;
136 if (!IsSecureConnect(member->cptr))
137 return 1;
138 }
139 return 0;
140 }
141
142 #define channel_has_insecure_users(x) channel_has_insecure_users_butone(x, NULL)
143
144 /* Set channel status of 'chptr' to be no longer secure (-Z) due to 'sptr'.
145 * sptr MAY be null!
146 */
issecure_unset(aChannel * chptr,aClient * sptr,int notice)147 void issecure_unset(aChannel *chptr, aClient *sptr, int notice)
148 {
149 if (notice)
150 {
151 if (chptr->mode.mode & MODE_AUDITORIUM)
152 sendto_channel_butserv(chptr, &me, ":%s NOTICE %s :User joined and is not connected through SSL, setting channel -Z (insecure)",
153 me.name, chptr->chname);
154 else
155 sendto_channel_butserv(chptr, &me, ":%s NOTICE %s :User '%s' joined and is not connected through SSL, setting channel -Z (insecure)",
156 me.name, chptr->chname, sptr->name);
157 }
158
159 chptr->mode.extmode &= ~EXTCMODE_ISSECURE;
160 sendto_channel_butserv(chptr, &me, ":%s MODE %s -Z", me.name, chptr->chname);
161 }
162
163
164 /* Set channel status of 'chptr' to be secure (+Z).
165 * Channel might have been insecure (or might not have been +z) and is
166 * now considered secure. If 'sptr' is non-NULL then we are now secure
167 * thanks to this user leaving the chat.
168 */
issecure_set(aChannel * chptr,aClient * sptr,int notice)169 void issecure_set(aChannel *chptr, aClient *sptr, int notice)
170 {
171 if (notice && sptr)
172 {
173 /* note that we have to skip 'sptr', since when this call is being made
174 * he is still considered a member of this channel.
175 */
176 sendto_channel_butserv_butone(chptr, &me, sptr, ":%s NOTICE %s :Now all users in the channel are connected through SSL, setting channel +Z (secure)",
177 me.name, chptr->chname);
178 } else if (notice)
179 {
180 /* note the missing word 'now' in next line */
181 sendto_channel_butserv(chptr, &me, ":%s NOTICE %s :All users in the channel are connected through SSL, setting channel +Z (secure)",
182 me.name, chptr->chname);
183 }
184 chptr->mode.extmode |= EXTCMODE_ISSECURE;
185 sendto_channel_butserv_butone(chptr, &me, sptr, ":%s MODE %s +Z", me.name, chptr->chname);
186 }
187
188 /* Note: the routines below (notably the 'if's) are written with speed in mind,
189 * so while they can be written shorter, they would only take longer to execute!
190 */
191
issecure_join(aClient * cptr,aClient * sptr,aChannel * chptr,char * parv[])192 DLLFUNC int issecure_join(aClient *cptr, aClient *sptr, aChannel *chptr, char *parv[])
193 {
194 /* Only care if chan already +zZ and the user joining is insecure (no need to count) */
195 if (IsSecureJoin(chptr) && IsSecureChanIndicated(chptr) && !IsSecureConnect(sptr) && !IsULine(sptr))
196 issecure_unset(chptr, sptr, 1);
197 return 0;
198 }
199
issecure_part(aClient * cptr,aClient * sptr,aChannel * chptr,char * comment)200 DLLFUNC int issecure_part(aClient *cptr, aClient *sptr, aChannel *chptr, char *comment)
201 {
202 /* Only care if chan is +z-Z and the user leaving is insecure, then count */
203 if (IsSecureJoin(chptr) && !IsSecureChanIndicated(chptr) && !IsSecureConnect(sptr) &&
204 !channel_has_insecure_users_butone(chptr, sptr))
205 issecure_set(chptr, sptr, 1);
206 return 0;
207 }
208
issecure_quit(aClient * sptr,char * comment)209 DLLFUNC int issecure_quit(aClient *sptr, char *comment)
210 {
211 Membership *membership;
212 aChannel *chptr;
213
214 for (membership = sptr->user->channel; membership; membership=membership->next)
215 {
216 chptr = membership->chptr;
217 /* Identical to part */
218 if (IsSecureJoin(chptr) && !IsSecureChanIndicated(chptr) &&
219 !IsSecureConnect(sptr) && !channel_has_insecure_users_butone(chptr, sptr))
220 issecure_set(chptr, sptr, 1);
221 }
222 return 0;
223 }
224
issecure_kick(aClient * cptr,aClient * sptr,aClient * victim,aChannel * chptr,char * comment)225 DLLFUNC int issecure_kick(aClient *cptr, aClient *sptr, aClient *victim, aChannel *chptr, char *comment)
226 {
227 /* Identical to part&quit, except we care about 'victim' and not 'sptr' */
228 if (IsSecureJoin(chptr) && !IsSecureChanIndicated(chptr) &&
229 !IsSecureConnect(victim) && !channel_has_insecure_users_butone(chptr, victim))
230 issecure_set(chptr, victim, 1);
231 return 0;
232 }
233
issecure_chanmode(aClient * cptr,aClient * sptr,aChannel * chptr,char * modebuf,char * parabuf,int sendts,int samode)234 DLLFUNC int issecure_chanmode(aClient *cptr, aClient *sptr, aChannel *chptr,
235 char *modebuf, char *parabuf, int sendts, int samode)
236 {
237 if (!strchr(modebuf, 'z'))
238 return 0; /* don't care */
239
240 if (IsSecureJoin(chptr))
241 {
242 /* +z is set, check if we need to +Z
243 * Note that we need to be careful as there is a possibility that we got here
244 * but the channel is ALREADY +z. Due to server2server MODE's.
245 */
246 if (channel_has_insecure_users(chptr))
247 {
248 /* Should be -Z, if not already */
249 if (IsSecureChanIndicated(chptr))
250 issecure_unset(chptr, NULL, 0); /* would be odd if we got here ;) */
251 } else {
252 /* Should be +Z, but check if it isn't already.. */
253 if (!IsSecureChanIndicated(chptr))
254 issecure_set(chptr, NULL, 0);
255 }
256 } else {
257 /* there was a -z, check if the channel is currently +Z and if so, set it -Z */
258 if (IsSecureChanIndicated(chptr))
259 issecure_unset(chptr, NULL, 0);
260 }
261 return 0;
262 }
263