]> jfr.im git - irc/quakenet/newserv.git/blame - glines/glines_buf.c
Use NL_CLONING for some of the trusts_policy messages.
[irc/quakenet/newserv.git] / glines / glines_buf.c
CommitLineData
ce11a200 1#include <stdarg.h>
cb581522
GB
2#include <stdio.h>
3#include <string.h>
31c690b7 4#include <assert.h>
a887af59 5#include "../lib/array.h"
a86fc0c4
GB
6#include "../lib/irc_string.h"
7#include "../irc/irc.h"
cb581522
GB
8#include "../control/control.h"
9#include "../trusts/trusts.h"
10#include "glines.h"
11
ce11a200
GB
12static int nextglinebufid = 1;
13glinebuf *glinebuflog[MAXGLINELOG] = {};
14int glinebuflogoffset = 0;
15
324b4e11
GB
16void glinebufinit(glinebuf *gbuf, int id) {
17 gbuf->id = id;
ce11a200 18 gbuf->comment = NULL;
33e09c2c 19 gbuf->commit = 0;
9f47116c 20 gbuf->amend = 0;
ce11a200 21 gbuf->glines = NULL;
fe262e64 22 gbuf->hitsvalid = 1;
bbb80250
GB
23 gbuf->userhits = 0;
24 gbuf->channelhits = 0;
a887af59 25 array_init(&gbuf->hits, sizeof(sstring *));
cb581522
GB
26}
27
28gline *glinebufadd(glinebuf *gbuf, const char *mask, const char *creator, const char *reason, time_t expire, time_t lastmod, time_t lifetime) {
324b4e11 29 gline *gl;
cb581522
GB
30
31 gl = makegline(mask); /* sets up nick,user,host,node and flags */
32
33 if (!gl) {
34 /* couldn't process gline mask */
35 Error("gline", ERR_WARNING, "Tried to add malformed G-Line %s!", mask);
36 return 0;
37 }
38
cb581522
GB
39 gl->creator = getsstring(creator, 255);
40
41 /* it's not unreasonable to assume gline is active, if we're adding a deactivated gline, we can remove this later */
42 gl->flags |= GLINE_ACTIVE;
43
44 gl->reason = getsstring(reason, 255);
45 gl->expire = expire;
46 gl->lastmod = lastmod;
47 gl->lifetime = lifetime;
48
ce11a200
GB
49 gl->next = gbuf->glines;
50 gbuf->glines = gl;
cb581522 51
33e09c2c
GB
52 gbuf->hitsvalid = 0;
53
cb581522
GB
54 return gl;
55}
56
57void glinebufaddbyip(glinebuf *gbuf, const char *user, struct irc_in_addr *ip, unsigned char bits, int flags, const char *creator, const char *reason, time_t expire, time_t lastmod, time_t lifetime) {
58 trusthost *th, *oth;
59 char mask[512];
60 unsigned char nodebits;
61
62 nodebits = getnodebits(ip);
63
64 if (!(flags & GLINE_IGNORE_TRUST)) {
65 th = th_getbyhost(ip);
66
67 if (th && (th->group->flags & TRUST_RELIABLE_USERNAME)) { /* Trust with reliable usernames */
a86fc0c4 68 for (oth = th->group->hosts; oth; oth = oth->next)
cb581522 69 glinebufaddbyip(gbuf, user, &oth->ip, oth->bits, flags | GLINE_ALWAYS_USER | GLINE_IGNORE_TRUST, creator, reason, expire, lastmod, lifetime);
a86fc0c4
GB
70
71 return;
cb581522
GB
72 }
73 }
74
75 if (!(flags & GLINE_ALWAYS_USER))
76 user = "*";
77
78 /* Widen gline to match the node mask. */
79 if (nodebits < bits)
80 bits = nodebits;
81
82 snprintf(mask, sizeof(mask), "%s@%s", user, trusts_cidr2str(ip, bits));
83
84 glinebufadd(gbuf, mask, creator, reason, expire, lastmod, lifetime);
85}
86
87void glinebufaddbynick(glinebuf *gbuf, nick *np, int flags, const char *creator, const char *reason, time_t expire, time_t lastmod, time_t lifetime) {
88 if (flags & GLINE_ALWAYS_NICK) {
89 char mask[512];
90 snprintf(mask, sizeof(mask), "%s!*@*", np->nick);
91 glinebufadd(gbuf, mask, creator, reason, expire, lastmod, lifetime);
92 } else {
93 glinebufaddbyip(gbuf, np->ident, &np->p_ipaddr, 128, flags, creator, reason, expire, lastmod, lifetime);
94 }
95}
96
33e09c2c 97void glinebufcounthits(glinebuf *gbuf, int *users, int *channels) {
cb581522 98 gline *gl;
a887af59 99 int i, hit, slot;
cb581522
GB
100 chanindex *cip;
101 channel *cp;
102 nick *np;
a887af59 103 char uhmask[512];
cb581522 104
33e09c2c
GB
105#if 0 /* Let's just do a new hit check anyway. */
106 if (gbuf->hitsvalid)
107 return;
108#endif
109
bbb80250
GB
110 gbuf->userhits = 0;
111 gbuf->channelhits = 0;
cb581522 112
a887af59
GB
113 for (i = 0; i < gbuf->hits.cursi; i++)
114 freesstring(((sstring **)gbuf->hits.content)[i]);
115
116 array_free(&gbuf->hits);
117 array_init(&gbuf->hits, sizeof(sstring *));
118
bbb80250
GB
119 for (i = 0; i<CHANNELHASHSIZE; i++) {
120 for (cip = chantable[i]; cip; cip = cip->next) {
121 cp = cip->channel;
cb581522 122
bbb80250
GB
123 if (!cp)
124 continue;
cb581522 125
bbb80250 126 hit = 0;
cb581522 127
bbb80250
GB
128 for (gl = gbuf->glines; gl; gl = gl->next) {
129 if (gline_match_channel(gl, cp)) {
130 hit = 1;
131 break;
cb581522 132 }
bbb80250 133 }
cb581522 134
bbb80250 135 if (hit) {
a887af59
GB
136 snprintf(uhmask, sizeof(uhmask), "channel: %s", cip->name->content);
137
bbb80250 138 gbuf->channelhits++;
a887af59
GB
139
140 slot = array_getfreeslot(&gbuf->hits);
141 ((sstring **)gbuf->hits.content)[slot] = getsstring(uhmask, 512);
cb581522
GB
142 }
143 }
144 }
145
bbb80250
GB
146 for (i = 0; i < NICKHASHSIZE; i++) {
147 for (np = nicktable[i]; np; np = np->next) {
148 hit = 0;
cb581522 149
bbb80250
GB
150 for (gl = gbuf->glines; gl; gl = gl->next) {
151 if (gline_match_nick(gl, np)) {
152 hit = 1;
153 break;
cb581522 154 }
bbb80250 155 }
cb581522 156
bbb80250 157 if (hit) {
33e09c2c
GB
158 snprintf(uhmask, sizeof(uhmask), "user: %s!%s@%s%s%s r(%s)", np->nick, np->ident, np->host->name->content,
159 (np->auth) ? "/" : "", (np->auth) ? np->authname : "", np->realname->name->content);
18845894 160
bbb80250 161 gbuf->userhits++;
a887af59
GB
162
163 slot = array_getfreeslot(&gbuf->hits);
164 ((sstring **)gbuf->hits.content)[slot] = getsstring(uhmask, 512);
cb581522
GB
165 }
166 }
167 }
33e09c2c
GB
168
169 gbuf->hitsvalid = 1;
170
bbb80250
GB
171 if (users)
172 *users = gbuf->userhits;
173
174 if (channels)
175 *channels = gbuf->channelhits;
cb581522
GB
176}
177
33e09c2c 178int glinebufchecksane(glinebuf *gbuf, nick *spewto, int overridesanity, int overridelimit) {
18845894
GB
179 gline *gl;
180 int users, channels, good;
a86fc0c4
GB
181 const char *hint;
182
33e09c2c 183 glinebufcounthits(gbuf, &users, &channels);
a86fc0c4 184
18845894
GB
185 if (!overridelimit) {
186 if (channels > MAXUSERGLINECHANNELHITS) {
187 controlreply(spewto, "G-Lines would hit %d channels. Limit is %d. Not setting G-Lines.", channels, MAXUSERGLINECHANNELHITS);
188 return 0;
189 } else if (users > MAXUSERGLINEUSERHITS) {
190 controlreply(spewto, "G-Lines would hit %d users. Limit is %d. Not setting G-Lines.", users, MAXUSERGLINEUSERHITS);
191 return 0;
192 }
193 }
194
195 good = 1;
a86fc0c4 196
18845894
GB
197 if (!overridesanity) {
198 /* Remove glines that fail the sanity check */
ce11a200 199 for (gl = gbuf->glines; gl; gl = gl->next) {
18845894 200 if (!isglinesane(gl, &hint)) {
56af56be
GB
201 controlreply(spewto, "Sanity check failed for G-Line on '%s' - Skipping: %s",
202 glinetostring(gl), hint);
18845894 203 good = 0;
56af56be 204 }
a86fc0c4
GB
205 }
206 }
207
18845894 208 return good;
a86fc0c4
GB
209}
210
56af56be 211void glinebufspew(glinebuf *gbuf, nick *spewto) {
a86fc0c4 212 gline *gl;
a887af59 213 int i;
324b4e11 214 char timebuf[30];
33e09c2c
GB
215
216 if (!gbuf->hitsvalid)
217 glinebufcounthits(gbuf, NULL, NULL);
218
219 if (gbuf->id == 0)
220 controlreply(spewto, "Uncommitted G-Line transaction.");
221 else
222 controlreply(spewto, "G-Line transaction ID %d", gbuf->id);
223
224 controlreply(spewto, "Comment: %s", (gbuf->comment) ? gbuf->comment->content : "(no comment)");
225
226 if (gbuf->commit) {
227 strftime(timebuf, sizeof(timebuf), "%d/%m/%y %H:%M:%S", localtime(&gbuf->commit));
228 controlreply(spewto, "Committed at: %s", timebuf);
229 }
230
9f47116c
GB
231 if (gbuf->amend) {
232 strftime(timebuf, sizeof(timebuf), "%d/%m/%y %H:%M:%S", localtime(&gbuf->amend));
eb8f36ca 233 controlreply(spewto, "Amended at: %s", timebuf);
33e09c2c
GB
234 }
235
324b4e11 236 controlreply(spewto, "Mask Duration Last modified Creator Reason");
ce11a200 237
324b4e11
GB
238 for (gl = gbuf->glines; gl; gl = gl->next) {
239 strftime(timebuf, sizeof(timebuf), "%d/%m/%y %H:%M:%S", localtime(&gl->lastmod));
240 controlreply(spewto, "%-40s %-20s %-20s %-20s %s", glinetostring(gl), longtoduration(gl->expire - gl->lastmod, 0), timebuf, gl->creator->content, gl->reason->content);
241 }
a887af59 242
33e09c2c 243 controlreply(spewto, "Hits");
a887af59 244
33e09c2c 245 for (i = 0; i < gbuf->hits.cursi; i++) {
a887af59 246 controlreply(spewto, "%s", ((sstring **)gbuf->hits.content)[i]->content);
33e09c2c
GB
247
248 if (i >= 500) {
249 controlreply(spewto, "More than 500 hits, list truncated.");
250 break;
251 }
252 }
31c690b7
GB
253
254 if (i == 0)
255 controlreply(spewto, "(no hits)");
a86fc0c4
GB
256}
257
324b4e11
GB
258void glinebufmerge(glinebuf *gbuf) {
259 /* TODO: reimplement */
260
261/*
262 if (gbuf->merge) {
263 /-* Check if an existing gline supercedes this mask *-/
264 for (sgl = gbuf->glines; sgl; sgl = sgl->next) {
265 if (gline_match_mask(sgl, gl)) {
266 freegline(gl);
267 return sgl;
268 }
269 }
270
271 /-* Remove older glines this gline matches *-/
272 for (pnext = &gbuf->glines; *pnext; pnext = &((*pnext)->next)) {
273 sgl = *pnext;
274
275 if (gline_match_mask(gl, sgl)) {
276 *pnext = sgl->next;
277 freegline(sgl);
278
279 if (!*pnext)
280 break;
281 }
282 }
283 }
284*/
285}
286
0c925dc0 287int glinebufcommit(glinebuf *gbuf, int propagate) {
cb581522 288 gline *gl, *next, *sgl;
fe262e64 289 int users, channels, id;
cb581522
GB
290
291 /* Sanity check */
33e09c2c 292 glinebufcounthits(gbuf, &users, &channels);
cb581522
GB
293
294 if (propagate && (users > MAXGLINEUSERHITS || channels > MAXGLINECHANNELHITS)) {
295 controlwall(NO_OPER, NL_GLINES, "G-Line buffer would hit %d users/%d channels. Not setting G-Lines.");
0b2e8a55 296 glinebufabort(gbuf);
0c925dc0 297 return 0;
cb581522
GB
298 }
299
31c690b7 300 /* Record the commit time */
324b4e11 301 time(&gbuf->commit);
ce11a200 302
fe262e64 303 id = glinebufwritelog(gbuf, propagate);
ce11a200 304
0c925dc0 305 /* Move glines to the global gline list */
ce11a200 306 for (gl = gbuf->glines; gl; gl = next) {
cb581522
GB
307 next = gl->next;
308
309 sgl = findgline(glinetostring(gl));
310
311 if (sgl) {
312 /* existing gline
313 * in 1.4, can update expire, reason etc
314 * in 1.3 can only activate/deactivate an existing gline */
315
316 if (gl->flags & GLINE_ACTIVE && !(sgl->flags & GLINE_ACTIVE))
317 gline_activate(sgl, 0, 0);
318 else if (!(gl->flags & GLINE_ACTIVE) && sgl->flags & GLINE_ACTIVE)
319 gline_deactivate(sgl, 0, 0);
320
ea0acfb3
GB
321#if SNIRCD_VERSION >= 140
322 sgl->expire = gl->expire;
323
324 if (gl->lifetime > sgl->lifetime)
325 sgl->lifetime = gl->lifetime;
326
327 freesstring(sgl->reason);
328 sgl->reason = getsstring(gl->reason, 512);
329#endif
330
cb581522
GB
331 freegline(gl);
332 gl = sgl;
333 } else {
334 gl->next = glinelist;
335 glinelist = gl;
336 }
337
31c690b7
GB
338 gl->glinebufid = id;
339
fe262e64 340 if (propagate)
cb581522 341 gline_propagate(gl);
ce11a200
GB
342 }
343
324b4e11 344 /* We've moved all glines to the global gline list. Clear glines link in the glinebuf. */
6eba1a37
GB
345 gbuf->glines = NULL;
346
0b2e8a55 347 glinebufabort(gbuf);
0c925dc0
GB
348
349 return id;
cb581522
GB
350}
351
0b2e8a55 352void glinebufabort(glinebuf *gbuf) {
cb581522 353 gline *gl, *next;
a887af59 354 int i;
cb581522 355
ce11a200 356 for (gl = gbuf->glines; gl; gl = next) {
cb581522
GB
357 next = gl->next;
358
359 freegline(gl);
360 }
0b2e8a55
GB
361
362 freesstring(gbuf->comment);
a887af59
GB
363
364 for (i = 0; i < gbuf->hits.cursi; i++)
365 freesstring(((sstring **)gbuf->hits.content)[i]);
366
367 array_free(&gbuf->hits);
0b2e8a55
GB
368}
369
370int glinebufundo(int id) {
371 glinebuf *gbl;
372 gline *gl, *sgl;
373 int i;
374
375 for (i = 0; i < MAXGLINELOG; i++) {
376 gbl = glinebuflog[i];
377
378 if (!gbl || gbl->id != id)
379 continue;
380
381 for (gl = gbl->glines; gl; gl = gl->next) {
382 sgl = findgline(glinetostring(gl));
383
384 if (!sgl)
385 continue;
31c690b7
GB
386
387 sgl->glinebufid = 0;
388
0b2e8a55
GB
389 gline_deactivate(sgl, 0, 1);
390 }
391
392 glinebufabort(gbl);
393 glinebuflog[i] = NULL;
394
395 return 1;
396 }
397
398 return 0;
cb581522 399}
ce11a200
GB
400
401void glinebufcommentf(glinebuf *gbuf, const char *format, ...) {
402 char comment[512];
403 va_list va;
404
405 va_start(va, format);
406 vsnprintf(comment, 511, format, va);
407 comment[511] = '\0';
408 va_end(va);
409
410 gbuf->comment = getsstring(comment, 512);
411}
412
413void glinebufcommentv(glinebuf *gbuf, const char *prefix, int cargc, char **cargv) {
414 char comment[512];
415 int i;
416
417 if (prefix)
418 strncpy(comment, prefix, sizeof(comment));
419 else
420 comment[0] = '\0';
421
422 for (i = 0; i < cargc; i++) {
423 if (comment[0])
424 strncat(comment, " ", sizeof(comment));
425
426 strncat(comment, cargv[i], sizeof(comment));
427 }
428
429 comment[511] = '\0';
430
431 gbuf->comment = getsstring(comment, 512);
432}
fe262e64
GB
433
434int glinebufwritelog(glinebuf *gbuf, int propagating) {
435 int i, slot;
436 gline *gl, *sgl;
437 glinebuf *gbl;
438
439 if (!gbuf->glines)
440 return 0; /* Don't waste log IDs on empty gline buffers */
441
442 gbl = NULL;
443
444 /* Find an existing log buffer with the same id */
445 if (gbuf->id != 0) {
446 for (i = 0; i < MAXGLINELOG; i++) {
447 if (!glinebuflog[i])
448 continue;
449
450 if (glinebuflog[i]->id == gbuf->id) {
451 gbl = glinebuflog[i];
452 gbl->amend = gbuf->commit;
453
454 /* We're going to re-insert this glinebuf, so remove it for now */
455 glinebuflog[i] = NULL;
456
457 break;
458 }
459 }
460 }
461
462 /* Find a recent glinebuf that's a close match */
463 if (!gbl && !propagating) {
464 for (i = 0; i < MAXGLINELOG; i++) {
465 if (!glinebuflog[i])
466 continue;
467
468 if (glinebuflog[i]->commit < getnettime() - 5 && glinebuflog[i]->amend < getnettime() - 5)
469 continue;
470
471 assert(glinebuflog[i]->glines);
472
473 if (strcmp(glinebuflog[i]->glines->creator->content, gbuf->glines->creator->content) != 0)
474 continue;
475
476 gbl = glinebuflog[i];
477 gbl->amend = gbuf->commit;
478
479 /* We're going to re-insert this glinebuf, so remove it for now */
480 glinebuflog[i] = NULL;
481
482 break;
483 }
484 }
485
486 /* Make a new glinebuf for the log */
487 if (!gbl && gbuf->id == 0) {
488 gbl = malloc(sizeof(glinebuf));
489 glinebufinit(gbl, (gbuf->id == 0) ? nextglinebufid++ : gbuf->id);
490
491 assert(gbl->hitsvalid);
492
493 if (gbuf->comment)
494 glinebufcommentf(gbl, "%s", gbuf->comment->content);
495 else if (!propagating)
ac034e04 496 glinebufcommentf(gbl, "G-Lines set by %s", gbuf->glines->creator->content);
fe262e64
GB
497
498 gbl->commit = gbuf->commit;
499 }
500
501 /* Save a duplicate of the glines in the log buffer */
502 for (gl = gbuf->glines; gl; gl = gl->next) {
503 sgl = glinedup(gl);
504 sgl->next = gbl->glines;
505 gbl->glines = sgl;
506 }
507
508 gbl->userhits += gbuf->userhits;
509 gbl->channelhits += gbuf->channelhits;
510
511 assert(gbuf->userhits + gbuf->channelhits == gbuf->hits.cursi);
512
513 for (i = 0; i < gbuf->hits.cursi; i++) {
514 slot = array_getfreeslot(&gbl->hits);
515 ((sstring **)gbl->hits.content)[slot] = getsstring(((sstring **)gbuf->hits.content)[i]->content, 512);
516 }
517
518 /* Log the transaction */
519 glinebuflogoffset++;
520
521 if (glinebuflogoffset >= MAXGLINELOG)
522 glinebuflogoffset = 0;
523
524 if (glinebuflog[glinebuflogoffset])
525 glinebufabort(glinebuflog[glinebuflogoffset]);
526
ac034e04 527 glinebuflog[glinebuflogoffset] = gbl;
fe262e64
GB
528
529 return gbl->id;
eb8f36ca 530}