]>
jfr.im git - irc/quakenet/newserv.git/blob - glines/glines_buf.c
5 #include "../lib/array.h"
6 #include "../lib/irc_string.h"
7 #include "../irc/irc.h"
8 #include "../control/control.h"
9 #include "../trusts/trusts.h"
12 static int nextglinebufid
= 1;
13 glinebuf
*glinebuflog
[MAXGLINELOG
] = {};
14 int glinebuflogoffset
= 0;
16 void glinebufinit(glinebuf
*gbuf
, int id
) {
24 gbuf
->channelhits
= 0;
25 array_init(&gbuf
->hits
, sizeof(sstring
*));
28 gline
*glinebufadd(glinebuf
*gbuf
, const char *mask
, const char *creator
, const char *reason
, time_t expire
, time_t lastmod
, time_t lifetime
) {
31 gl
= makegline(mask
); /* sets up nick,user,host,node and flags */
34 /* couldn't process gline mask */
35 Error("gline", ERR_WARNING
, "Tried to add malformed G-Line %s!", mask
);
39 gl
->creator
= getsstring(creator
, 255);
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
;
44 gl
->reason
= getsstring(reason
, 255);
46 gl
->lastmod
= lastmod
;
47 gl
->lifetime
= lifetime
;
49 gl
->next
= gbuf
->glines
;
57 char *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
) {
59 static char mask
[512];
60 unsigned char nodebits
;
62 nodebits
= getnodebits(ip
);
64 if (!(flags
& GLINE_IGNORE_TRUST
)) {
65 th
= th_getbyhost(ip
);
67 if (th
&& (th
->group
->flags
& TRUST_RELIABLE_USERNAME
)) { /* Trust with reliable usernames */
68 for (oth
= th
->group
->hosts
; oth
; oth
= oth
->next
)
69 glinebufaddbyip(gbuf
, user
, &oth
->ip
, oth
->bits
, flags
| GLINE_ALWAYS_USER
| GLINE_IGNORE_TRUST
, creator
, reason
, expire
, lastmod
, lifetime
);
71 snprintf(mask
, sizeof(mask
), "%s@%s/tg%u", user
, (bits
== 128) ? IPtostr(*ip
) : CIDRtostr(*ip
, bits
), th
->group
->id
);
76 if (!(flags
& GLINE_ALWAYS_USER
))
79 /* Widen gline to match the node mask. */
83 snprintf(mask
, sizeof(mask
), "%s@%s", user
, (bits
== 128) ? IPtostr(*ip
) : CIDRtostr(*ip
, bits
));
85 glinebufadd(gbuf
, mask
, creator
, reason
, expire
, lastmod
, lifetime
);
89 char *glinebufaddbynick(glinebuf
*gbuf
, nick
*np
, int flags
, const char *creator
, const char *reason
, time_t expire
, time_t lastmod
, time_t lifetime
) {
90 if (flags
& GLINE_ALWAYS_NICK
) {
91 static char mask
[512];
92 snprintf(mask
, sizeof(mask
), "%s!*@*", np
->nick
);
93 glinebufadd(gbuf
, mask
, creator
, reason
, expire
, lastmod
, lifetime
);
96 return glinebufaddbyip(gbuf
, np
->ident
, &np
->ipaddress
, 128, flags
, creator
, reason
, expire
, lastmod
, lifetime
);
100 void glinebufaddbywhowas(glinebuf
*gbuf
, whowas
*ww
, int flags
, const char *creator
, const char *reason
, time_t expire
, time_t lastmod
, time_t lifetime
) {
101 nick
*np
= &ww
->nick
;
103 if (flags
& GLINE_ALWAYS_NICK
) {
105 snprintf(mask
, sizeof(mask
), "%s!*@*", np
->nick
);
106 glinebufadd(gbuf
, mask
, creator
, reason
, expire
, lastmod
, lifetime
);
108 glinebufaddbyip(gbuf
, np
->ident
, &np
->ipaddress
, 128, flags
, creator
, reason
, expire
, lastmod
, lifetime
);
112 void glinebufcounthits(glinebuf
*gbuf
, int *users
, int *channels
) {
120 #if 0 /* Let's just do a new hit check anyway. */
126 gbuf
->channelhits
= 0;
128 for (i
= 0; i
< gbuf
->hits
.cursi
; i
++)
129 freesstring(((sstring
**)gbuf
->hits
.content
)[i
]);
131 array_free(&gbuf
->hits
);
132 array_init(&gbuf
->hits
, sizeof(sstring
*));
134 for (i
= 0; i
<CHANNELHASHSIZE
; i
++) {
135 for (cip
= chantable
[i
]; cip
; cip
= cip
->next
) {
143 for (gl
= gbuf
->glines
; gl
; gl
= gl
->next
) {
144 if (gline_match_channel(gl
, cp
)) {
151 snprintf(uhmask
, sizeof(uhmask
), "channel: %s", cip
->name
->content
);
155 slot
= array_getfreeslot(&gbuf
->hits
);
156 ((sstring
**)gbuf
->hits
.content
)[slot
] = getsstring(uhmask
, 512);
161 for (i
= 0; i
< NICKHASHSIZE
; i
++) {
162 for (np
= nicktable
[i
]; np
; np
= np
->next
) {
165 for (gl
= gbuf
->glines
; gl
; gl
= gl
->next
) {
166 if (gline_match_nick(gl
, np
)) {
173 snprintf(uhmask
, sizeof(uhmask
), "user: %s!%s@%s%s%s r(%s)", np
->nick
, np
->ident
, np
->host
->name
->content
,
174 (np
->auth
) ? "/" : "", (np
->auth
) ? np
->authname
: "", np
->realname
->name
->content
);
178 slot
= array_getfreeslot(&gbuf
->hits
);
179 ((sstring
**)gbuf
->hits
.content
)[slot
] = getsstring(uhmask
, 512);
187 *users
= gbuf
->userhits
;
190 *channels
= gbuf
->channelhits
;
193 int glinebufchecksane(glinebuf
*gbuf
, nick
*spewto
, int overridesanity
, int overridelimit
) {
195 int users
, channels
, good
;
198 glinebufcounthits(gbuf
, &users
, &channels
);
200 if (!overridelimit
) {
201 if (channels
> MAXUSERGLINECHANNELHITS
) {
202 controlreply(spewto
, "G-Lines would hit %d channels. Limit is %d. Not setting G-Lines.", channels
, MAXUSERGLINECHANNELHITS
);
204 } else if (users
> MAXUSERGLINEUSERHITS
) {
205 controlreply(spewto
, "G-Lines would hit %d users. Limit is %d. Not setting G-Lines.", users
, MAXUSERGLINEUSERHITS
);
212 if (!overridesanity
) {
213 /* Remove glines that fail the sanity check */
214 for (gl
= gbuf
->glines
; gl
; gl
= gl
->next
) {
215 if (!isglinesane(gl
, &hint
)) {
216 controlreply(spewto
, "Sanity check failed for G-Line on '%s' - Skipping: %s",
217 glinetostring(gl
), hint
);
226 void glinebufspew(glinebuf
*gbuf
, nick
*spewto
) {
229 char timebuf
[30], lastmod
[30];
231 if (!gbuf
->hitsvalid
)
232 glinebufcounthits(gbuf
, NULL
, NULL
);
235 controlreply(spewto
, "Uncommitted G-Line transaction.");
237 controlreply(spewto
, "G-Line transaction ID %d", gbuf
->id
);
239 controlreply(spewto
, "Comment: %s", (gbuf
->comment
) ? gbuf
->comment
->content
: "(no comment)");
242 strftime(timebuf
, sizeof(timebuf
), "%d/%m/%y %H:%M:%S", localtime(&gbuf
->commit
));
243 controlreply(spewto
, "Committed at: %s", timebuf
);
247 strftime(timebuf
, sizeof(timebuf
), "%d/%m/%y %H:%M:%S", localtime(&gbuf
->amend
));
248 controlreply(spewto
, "Amended at: %s", timebuf
);
251 controlreply(spewto
, "Mask Expiry Last modified Creator Reason");
253 for (gl
= gbuf
->glines
; gl
; gl
= gl
->next
) {
254 strftime(timebuf
, sizeof(timebuf
), "%d/%m/%y %H:%M:%S", localtime(&gl
->expire
));
256 if (gl
->lastmod
== 0)
257 strncpy(lastmod
, "<ulined>", sizeof(lastmod
));
259 strftime(lastmod
, sizeof(lastmod
), "%d/%m/%y %H:%M:%S", localtime(&gl
->lastmod
));
261 controlreply(spewto
, "%-40s %-20s %-20s %-25s %s", glinetostring(gl
), timebuf
, lastmod
, gl
->creator
->content
, gl
->reason
? gl
->reason
->content
: "");
264 controlreply(spewto
, "Hits");
266 for (i
= 0; i
< gbuf
->hits
.cursi
; i
++) {
267 controlreply(spewto
, "%s", ((sstring
**)gbuf
->hits
.content
)[i
]->content
);
270 controlreply(spewto
, "More than 500 hits, list truncated.");
276 controlreply(spewto
, "(no hits)");
279 void glinebufmerge(glinebuf
*gbuf
) {
280 /* TODO: reimplement */
284 /-* Check if an existing gline supercedes this mask *-/
285 for (sgl = gbuf->glines; sgl; sgl = sgl->next) {
286 if (gline_match_mask(sgl, gl)) {
292 /-* Remove older glines this gline matches *-/
293 for (pnext = &gbuf->glines; *pnext; pnext = &((*pnext)->next)) {
296 if (gline_match_mask(gl, sgl)) {
308 int glinebufcommit(glinebuf
*gbuf
, int propagate
) {
309 gline
*gl
, *next
, *sgl
;
310 int users
, channels
, id
;
313 glinebufcounthits(gbuf
, &users
, &channels
);
315 if (propagate
&& (users
> MAXGLINEUSERHITS
|| channels
> MAXGLINECHANNELHITS
)) {
316 controlwall(NO_OPER
, NL_GLINES_AUTO
, "G-Line buffer would hit %d users/%d channels. Not setting G-Lines.");
321 /* Record the commit time */
324 id
= glinebufwritelog(gbuf
, propagate
);
326 /* Move glines to the global gline list */
327 for (gl
= gbuf
->glines
; gl
; gl
= next
) {
330 sgl
= findgline(glinetostring(gl
));
334 * in 1.4, can update expire, reason etc
335 * in 1.3 can only activate/deactivate an existing gline */
337 if (gl
->flags
& GLINE_ACTIVE
&& !(sgl
->flags
& GLINE_ACTIVE
))
338 gline_activate(sgl
, 0, 0);
339 else if (!(gl
->flags
& GLINE_ACTIVE
) && sgl
->flags
& GLINE_ACTIVE
)
340 gline_deactivate(sgl
, 0, 0);
342 #if SNIRCD_VERSION >= 140
343 sgl
->expire
= gl
->expire
;
345 if (gl
->lifetime
> sgl
->lifetime
)
346 sgl
->lifetime
= gl
->lifetime
;
348 freesstring(sgl
->reason
);
349 sgl
->reason
= getsstring(gl
->reason
, 512);
355 gl
->next
= glinelist
;
365 /* We've moved all glines to the global gline list. Clear glines link in the glinebuf. */
373 void glinebufabort(glinebuf
*gbuf
) {
377 for (gl
= gbuf
->glines
; gl
; gl
= next
) {
383 freesstring(gbuf
->comment
);
385 for (i
= 0; i
< gbuf
->hits
.cursi
; i
++)
386 freesstring(((sstring
**)gbuf
->hits
.content
)[i
]);
388 array_free(&gbuf
->hits
);
391 int glinebufundo(int id
) {
396 for (i
= 0; i
< MAXGLINELOG
; i
++) {
397 gbl
= glinebuflog
[i
];
399 if (!gbl
|| gbl
->id
!= id
)
402 for (gl
= gbl
->glines
; gl
; gl
= gl
->next
) {
403 sgl
= findgline(glinetostring(gl
));
410 gline_deactivate(sgl
, 0, 1);
414 glinebuflog
[i
] = NULL
;
422 void glinebufcommentf(glinebuf
*gbuf
, const char *format
, ...) {
426 va_start(va
, format
);
427 vsnprintf(comment
, 511, format
, va
);
431 gbuf
->comment
= getsstring(comment
, 512);
434 void glinebufcommentv(glinebuf
*gbuf
, const char *prefix
, int cargc
, char **cargv
) {
439 strncpy(comment
, prefix
, sizeof(comment
));
443 for (i
= 0; i
< cargc
; i
++) {
445 strncat(comment
, " ", sizeof(comment
));
447 strncat(comment
, cargv
[i
], sizeof(comment
));
452 gbuf
->comment
= getsstring(comment
, 512);
455 int glinebufwritelog(glinebuf
*gbuf
, int propagating
) {
461 return 0; /* Don't waste log IDs on empty gline buffers */
465 /* Find an existing log buffer with the same id */
467 for (i
= 0; i
< MAXGLINELOG
; i
++) {
471 if (glinebuflog
[i
]->id
== gbuf
->id
) {
472 gbl
= glinebuflog
[i
];
473 gbl
->amend
= gbuf
->commit
;
475 /* We're going to re-insert this glinebuf, so remove it for now */
476 glinebuflog
[i
] = NULL
;
483 /* Find a recent glinebuf that's a close match */
484 if (!gbl
&& !propagating
) {
485 for (i
= 0; i
< MAXGLINELOG
; i
++) {
489 if (glinebuflog
[i
]->commit
< getnettime() - 5 && glinebuflog
[i
]->amend
< getnettime() - 5)
492 assert(glinebuflog
[i
]->glines
);
494 if (strcmp(glinebuflog
[i
]->glines
->creator
->content
, gbuf
->glines
->creator
->content
) != 0)
497 gbl
= glinebuflog
[i
];
498 gbl
->amend
= gbuf
->commit
;
500 /* We're going to re-insert this glinebuf, so remove it for now */
501 glinebuflog
[i
] = NULL
;
507 /* Make a new glinebuf for the log */
509 gbl
= malloc(sizeof(glinebuf
));
510 glinebufinit(gbl
, (gbuf
->id
== 0) ? nextglinebufid
++ : gbuf
->id
);
512 assert(gbl
->hitsvalid
);
515 glinebufcommentf(gbl
, "%s", gbuf
->comment
->content
);
516 else if (!propagating
)
517 glinebufcommentf(gbl
, "G-Lines set by %s", gbuf
->glines
->creator
->content
);
519 gbl
->commit
= gbuf
->commit
;
522 /* Save a duplicate of the glines in the log buffer */
523 for (gl
= gbuf
->glines
; gl
; gl
= gl
->next
) {
525 sgl
->next
= gbl
->glines
;
529 gbl
->userhits
+= gbuf
->userhits
;
530 gbl
->channelhits
+= gbuf
->channelhits
;
532 assert(gbuf
->userhits
+ gbuf
->channelhits
== gbuf
->hits
.cursi
);
534 for (i
= 0; i
< gbuf
->hits
.cursi
; i
++) {
535 slot
= array_getfreeslot(&gbl
->hits
);
536 ((sstring
**)gbl
->hits
.content
)[slot
] = getsstring(((sstring
**)gbuf
->hits
.content
)[i
]->content
, 512);
539 /* Log the transaction */
542 if (glinebuflogoffset
>= MAXGLINELOG
)
543 glinebuflogoffset
= 0;
545 if (glinebuflog
[glinebuflogoffset
])
546 glinebufabort(glinebuflog
[glinebuflogoffset
]);
548 glinebuflog
[glinebuflogoffset
] = gbl
;