]> jfr.im git - irc/quakenet/newserv.git/blame - glines/glines.c
Send error messages about failed glines to the user rather than controllwalling them.
[irc/quakenet/newserv.git] / glines / glines.c
CommitLineData
8f128e0d 1#include <stdio.h>
a44fc5f7
GB
2#include <string.h>
3#include <assert.h>
a473a1be 4#include "../lib/irc_string.h"
c4610da5 5#include "../lib/version.h"
580103bc 6#include "../core/schedule.h"
813c5b73 7#include "../irc/irc.h"
813c5b73 8#include "../trusts/trusts.h"
a473a1be 9#include "../control/control.h"
813c5b73
CP
10#include "glines.h"
11
c4610da5
GB
12MODULE_VERSION("");
13
580103bc
GB
14static void glines_sched_save(void *arg);
15
a44fc5f7
GB
16void _init() {
17 /* If we're connected to IRC, force a disconnect. */
18 if (connected) {
c684f472
GB
19 irc_send("%s SQ %s 0 :Resync [adding gline support]", mynumeric->content, myserver->content);
20 irc_disconnected();
a44fc5f7
GB
21 }
22
23 registerserverhandler("GL", handleglinemsg, 6);
24 registerhook(HOOK_CORE_STATSREQUEST, handleglinestats);
a44fc5f7
GB
25}
26
27void _fini() {
28 deregisterserverhandler("GL", handleglinemsg);
29 deregisterhook(HOOK_CORE_STATSREQUEST, handleglinestats);
30}
31
c684f472
GB
32int gline_match_nick(gline *gl, nick *np) {
33 if (gl->flags & GLINE_BADCHAN)
34 return 0;
35
36 if (gl->flags & GLINE_REALNAME) {
96662a86 37 if (gl->user && match(gl->user->content, np->realname->name->content) != 0)
c684f472
GB
38 return 0;
39
40 return 1;
41 }
42
43 if (gl->nick && match(gl->nick->content, np->nick) != 0)
44 return 0;
45
46 if (gl->user && match(gl->user->content, np->ident) != 0)
47 return 0;
48
49 if (gl->flags & GLINE_IPMASK) {
50 if (!ipmask_check(&gl->ip, &np->p_ipaddr, gl->bits))
51 return 0;
52 } else {
53 if (gl->host && match(gl->host->content, np->host->name->content) != 0)
54 return 0;
55 }
56
57 return 1;
58}
59
60int gline_match_channel(gline *gl, channel *cp) {
61 if (!(gl->flags & GLINE_BADCHAN))
62 return 0;
63
64 if (match(gl->user->content, cp->index->name->content) != 0)
65 return 0;
66
67 return 1;
68}
69
96662a86 70gline *findgline(const char *mask) {
c684f472 71 gline *gl, *next;
a44fc5f7
GB
72 gline *globalgline;
73 time_t curtime = time(0);
74
c684f472
GB
75 globalgline = makegline(mask);
76
77 if (!globalgline)
78 return NULL; /* gline mask couldn't be processed */
a44fc5f7 79
c684f472
GB
80 for (gl = glinelist; gl; gl = next) {
81 next = gl->next;
a44fc5f7
GB
82
83 if (gl->lifetime <= curtime) {
84 removegline(gl);
85 continue;
86 } else if (gl->expire <= curtime) {
87 gl->flags &= ~GLINE_ACTIVE;
88 }
89
90 if (glineequal(globalgline, gl)) {
91 freegline(globalgline);
92 return gl;
93 }
94 }
95
96 freegline(globalgline);
97 return 0;
98}
99
331ecd41 100void gline_activate(gline *agline, time_t lastmod, int propagate) {
a44fc5f7 101 time_t now = getnettime();
20447d72 102
a44fc5f7
GB
103 agline->flags |= GLINE_ACTIVE;
104
331ecd41 105 if (lastmod)
a44fc5f7 106 agline->lastmod = lastmod;
331ecd41
GB
107 else if (now <= agline->lastmod)
108 agline->lastmod++;
109 else
110 agline->lastmod = now;
a44fc5f7
GB
111
112 if (propagate)
113 gline_propagate(agline);
a44fc5f7
GB
114}
115
331ecd41 116void gline_deactivate(gline *agline, time_t lastmod, int propagate) {
a44fc5f7 117 time_t now = getnettime();
20447d72 118
21ae66d1
GB
119 if (agline->lastmod == 0) {
120 Error("gline", ERR_WARNING, "Tried to deactivate gline with lastmod == 0: %s", glinetostring(agline));
121 return;
122 }
123
20447d72
GB
124 agline->flags &= ~GLINE_ACTIVE;
125
126 if (lastmod)
127 agline->lastmod = lastmod;
128 else if (now <= agline->lastmod)
129 agline->lastmod++;
130 else
131 agline->lastmod = now;
132
133 if (propagate)
134 gline_propagate(agline);
135}
136
137void gline_destroy(gline *agline, time_t lastmod, int propagate) {
138 time_t now = getnettime();
139
a44fc5f7 140 agline->flags &= ~GLINE_ACTIVE;
20447d72 141 agline->flags |= GLINE_DESTROYED;
a44fc5f7 142
21ae66d1
GB
143 if (agline->lastmod == 0) {
144 Error("gline", ERR_WARNING, "Tried to destroy gline with lastmod == 0: %s", glinetostring(agline));
145 return;
146 }
147
331ecd41 148 if (lastmod)
a44fc5f7 149 agline->lastmod = lastmod;
331ecd41
GB
150 else if (now <= agline->lastmod)
151 agline->lastmod++;
152 else
153 agline->lastmod = now;
a44fc5f7
GB
154
155 if (propagate)
156 gline_propagate(agline);
20447d72
GB
157
158 removegline(agline);
a44fc5f7
GB
159}
160
161void gline_propagate(gline *agline) {
20447d72
GB
162 if (agline->flags & GLINE_DESTROYED) {
163 controlwall(NO_OPER, NL_GLINES, "Destroying G-Line on '%s' lasting %s with reason '%s', created by: %s",
164 glinetostring(agline), longtoduration(agline->expire-getnettime(), 0),
165 agline->reason->content, agline->creator->content);
166
184891f7 167#if 0
20447d72
GB
168 irc_send("%s GL * %%-%s %lu %lu :%s\r\n", mynumeric->content,
169 glinetostring(agline), agline->expire - getnettime(),
170 agline->lastmod, agline->reason->content);
171#else
172 controlwall(NO_OPER, NL_GLINES, "%s GL * %%-%s %lu %lu :%s\r\n", mynumeric->content,
173 glinetostring(agline), agline->expire - getnettime(),
174 agline->lastmod, agline->reason->content);
175#endif
176 } else if (agline->flags & GLINE_ACTIVE) {
d892838f 177 controlwall(NO_OPER, NL_GLINES, "Activating G-Line on '%s' lasting %s created by %s with reason '%s'",
c684f472 178 glinetostring(agline), longtoduration(agline->expire-getnettime(), 0),
d892838f 179 agline->creator->content, agline->reason->content);
5649ec17 180
184891f7 181#if 0
c684f472
GB
182 irc_send("%s GL * +%s %lu %lu :%s\r\n", mynumeric->content,
183 glinetostring(agline), agline->expire - getnettime(),
184 agline->lastmod, agline->reason->content);
cb581522 185#else
5649ec17
GB
186 controlwall(NO_OPER, NL_GLINES, "%s GL * +%s %lu %lu :%s\r\n", mynumeric->content,
187 glinetostring(agline), agline->expire - getnettime(),
188 agline->lastmod, agline->reason->content);
cb581522 189#endif
a44fc5f7 190 } else {
d892838f
GB
191 controlwall(NO_OPER, NL_GLINES, "Deactivating G-Line on '%s' lasting %s created by %s with reason '%s'",
192 glinetostring(agline), longtoduration(agline->expire-getnettime(), 0),
193 agline->creator->content, agline->reason->content);
5649ec17 194
184891f7 195#if 0
c684f472
GB
196 irc_send("%s GL * -%s %lu %lu :%s\r\n", mynumeric->content,
197 glinetostring(agline), agline->expire - getnettime(),
198 agline->lastmod, agline->reason->content);
cb581522 199#else
5649ec17
GB
200 controlwall(NO_OPER, NL_GLINES, "%s GL * -%s %lu %lu :%s\r\n", mynumeric->content,
201 glinetostring(agline), agline->expire - getnettime(),
202 agline->lastmod, agline->reason->content);
cb581522 203#endif
a44fc5f7
GB
204 }
205}
206
207/* returns non-zero if the glines are exactly the same */
208int glineequal(gline *gla, gline *glb) {
c684f472 209 if ((gla->flags & GLINE_BADCHAN) != (glb->flags & GLINE_BADCHAN))
a44fc5f7
GB
210 return 0;
211
c684f472 212 if ((gla->flags & GLINE_REALNAME) != (glb->flags & GLINE_REALNAME))
a44fc5f7
GB
213 return 0;
214
c684f472
GB
215 if ((gla->flags & GLINE_IPMASK) != (glb->flags & GLINE_IPMASK))
216 return 0;
217
218 if ((!gla->nick && glb->nick) || (gla->nick && !glb->nick))
a44fc5f7
GB
219 return 0;
220
c684f472 221 if (gla->nick && ircd_strcmp(gla->nick->content, glb->nick->content) != 0)
a44fc5f7
GB
222 return 0;
223
c684f472 224 if ((!gla->user && glb->user) || (gla->user && !glb->user))
a44fc5f7
GB
225 return 0;
226
c684f472 227 if (gla->user && ircd_strcmp(gla->user->content, glb->user->content) != 0)
a44fc5f7
GB
228 return 0;
229
c684f472
GB
230 if (gla->flags & GLINE_IPMASK) {
231 if (gla->bits != glb->bits)
232 return 0;
233
234 if (!ipmask_check(&gla->ip, &glb->ip, gla->bits))
235 return 0;
236 } else {
237 if ((!gla->host && glb->host) || (gla->host && !glb->host))
238 return 0;
239
240 if (gla->host && ircd_strcmp(gla->host->content, glb->host->content) != 0)
241 return 0;
242 }
243
a44fc5f7
GB
244 return 1;
245}
246
247/* returns non-zero on match */
c684f472
GB
248int gline_match_mask(gline *gla, gline *glb) {
249 if ((gla->flags & GLINE_BADCHAN) != (glb->flags & GLINE_BADCHAN))
a44fc5f7
GB
250 return 0;
251
c684f472 252 if ((gla->flags & GLINE_REALNAME) != (glb->flags & GLINE_REALNAME))
a44fc5f7
GB
253 return 0;
254
c684f472 255 if ((gla->flags & GLINE_IPMASK) != (glb->flags & GLINE_IPMASK))
a44fc5f7
GB
256 return 0;
257
c684f472 258 if (gla->nick && !glb->nick)
a44fc5f7
GB
259 return 0;
260
c684f472 261 if (gla->nick && glb->nick && match(gla->nick->content, glb->nick->content) != 0)
a44fc5f7
GB
262 return 0;
263
c684f472 264 if (gla->user && !glb->user)
a44fc5f7
GB
265 return 0;
266
c684f472
GB
267 if (gla->user && glb->user && match(gla->user->content, glb->user->content) != 0)
268 return 0;
a44fc5f7 269
c684f472
GB
270 if (gla->flags & GLINE_IPMASK) {
271 if (gla->bits > glb->bits)
272 return 0;
a44fc5f7 273
c684f472
GB
274 if (!ipmask_check(&gla->ip, &glb->ip, gla->bits))
275 return 0;
276 } else {
277 if (gla->host && !glb->host)
278 return 0;
279
280 if (gla->host && glb->host && match(gla->host->content, glb->host->content) != 0)
281 return 0;
282 }
283
284 return 1;
a44fc5f7
GB
285}
286
a86fc0c4
GB
287int isglinesane(gline *gl, const char **hint) {
288 int wildcard, nowildcardcount;
289 char *pos;
290 trusthost *th;
291
292 /* Hits all realnames. */
293 if ((gl->flags & GLINE_REALNAME) && !gl->user) {
294 *hint = "Matches all realnames.";
295 return 0;
296 }
297
298 /* Hits all local/non-local channels. */
299 if ((gl->flags & GLINE_BADCHAN) && (strcmp(gl->user->content, "&*") == 0 || strcmp(gl->user->content, "#*") == 0)) {
300 *hint = "Matches all local/non-local channels.";
301 return 0;
302 }
303
fb89902c
GB
304 /* Hostmask is too long. */
305 if (!(gl->flags & (GLINE_BADCHAN | GLINE_REALNAME)) &&
306 ((gl->nick && strlen(gl->nick->content) > NICKLEN) ||
307 (gl->user && strlen(gl->user->content) > USERLEN) ||
308 (gl->host && strlen(gl->host->content) > HOSTLEN))) {
309 *hint = "Hostmask components are too long.";
310 return 0;
311 }
312
521d4392
GB
313 /* Skip the other checks for nickname glines. */
314 if (gl->nick)
315 return 1;
316
a86fc0c4
GB
317 /* Mask wider than /16 for IPv4 or /32 for IPv6. */
318 if ((gl->flags & GLINE_IPMASK) && gl->bits < (irc_in_addr_is_ipv4(&gl->ip) ? (96 + 16) : 32)) {
319 *hint = "CIDR mask too wide.";
320 return 0;
321 }
322
323 /* Doesn't have at least two non-wildcarded host components. */
324 if (gl->flags & GLINE_HOSTMASK) {
325 nowildcardcount = 0;
326
327 wildcard = 0;
328 pos = gl->host->content;
329
330 for (;;) {
331 switch (*pos) {
332 case '*':
333 /* fall through */
334 case '?':
335 wildcard = 1;
336 break;
337
338 case '.':
339 case '\0':
340 if (!wildcard)
341 nowildcardcount++;
342 else
343 wildcard = 0;
344
345 if (*pos == '\0')
346 pos = NULL; /* Leave the loop. */
347
348 break;
349 }
350
351 if (pos)
352 pos++;
353 else
354 break;
355 }
356
357 if (nowildcardcount < 2) {
358 *hint = "Needs at least 2 non-wildcarded host components.";
359 return 0;
360 }
361 }
362
363 /* Wildcard username match for trusted host with reliable usernames. */
61702c86 364 if ((gl->flags & GLINE_IPMASK) && (!gl->user || strchr(gl->user->content, '*') || strchr(gl->user->content, '?'))) {
a86fc0c4
GB
365 th = th_getbyhost(&gl->ip);
366
367 if (th && (th->group->flags & TRUST_RELIABLE_USERNAME)) {
368 *hint = "Wildcard username match for a trusted host that has reliable usernames.";
369 return 0;
370 }
371 }
372
373 return 1;
374}