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