]>
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 void 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
) {
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
);
75 if (!(flags
& GLINE_ALWAYS_USER
))
78 /* Widen gline to match the node mask. */
82 snprintf(mask
, sizeof(mask
), "%s@%s", user
, (bits
== 128) ? IPtostr(*ip
) : CIDRtostr(*ip
, bits
));
84 glinebufadd(gbuf
, mask
, creator
, reason
, expire
, lastmod
, lifetime
);
87 void 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
) {
90 snprintf(mask
, sizeof(mask
), "%s!*@*", np
->nick
);
91 glinebufadd(gbuf
, mask
, creator
, reason
, expire
, lastmod
, lifetime
);
93 glinebufaddbyip(gbuf
, np
->ident
, &np
->ipaddress
, 128, flags
, creator
, reason
, expire
, lastmod
, lifetime
);
97 void glinebufaddbywhowas(glinebuf
*gbuf
, whowas
*ww
, int flags
, const char *creator
, const char *reason
, time_t expire
, time_t lastmod
, time_t lifetime
) {
100 if (flags
& GLINE_ALWAYS_NICK
) {
102 snprintf(mask
, sizeof(mask
), "%s!*@*", np
->nick
);
103 glinebufadd(gbuf
, mask
, creator
, reason
, expire
, lastmod
, lifetime
);
105 glinebufaddbyip(gbuf
, np
->ident
, &np
->ipaddress
, 128, flags
, creator
, reason
, expire
, lastmod
, lifetime
);
109 void glinebufcounthits(glinebuf
*gbuf
, int *users
, int *channels
) {
117 #if 0 /* Let's just do a new hit check anyway. */
123 gbuf
->channelhits
= 0;
125 for (i
= 0; i
< gbuf
->hits
.cursi
; i
++)
126 freesstring(((sstring
**)gbuf
->hits
.content
)[i
]);
128 array_free(&gbuf
->hits
);
129 array_init(&gbuf
->hits
, sizeof(sstring
*));
131 for (i
= 0; i
<CHANNELHASHSIZE
; i
++) {
132 for (cip
= chantable
[i
]; cip
; cip
= cip
->next
) {
140 for (gl
= gbuf
->glines
; gl
; gl
= gl
->next
) {
141 if (gline_match_channel(gl
, cp
)) {
148 snprintf(uhmask
, sizeof(uhmask
), "channel: %s", cip
->name
->content
);
152 slot
= array_getfreeslot(&gbuf
->hits
);
153 ((sstring
**)gbuf
->hits
.content
)[slot
] = getsstring(uhmask
, 512);
158 for (i
= 0; i
< NICKHASHSIZE
; i
++) {
159 for (np
= nicktable
[i
]; np
; np
= np
->next
) {
162 for (gl
= gbuf
->glines
; gl
; gl
= gl
->next
) {
163 if (gline_match_nick(gl
, np
)) {
170 snprintf(uhmask
, sizeof(uhmask
), "user: %s!%s@%s%s%s r(%s)", np
->nick
, np
->ident
, np
->host
->name
->content
,
171 (np
->auth
) ? "/" : "", (np
->auth
) ? np
->authname
: "", np
->realname
->name
->content
);
175 slot
= array_getfreeslot(&gbuf
->hits
);
176 ((sstring
**)gbuf
->hits
.content
)[slot
] = getsstring(uhmask
, 512);
184 *users
= gbuf
->userhits
;
187 *channels
= gbuf
->channelhits
;
190 int glinebufchecksane(glinebuf
*gbuf
, nick
*spewto
, int overridesanity
, int overridelimit
) {
192 int users
, channels
, good
;
195 glinebufcounthits(gbuf
, &users
, &channels
);
197 if (!overridelimit
) {
198 if (channels
> MAXUSERGLINECHANNELHITS
) {
199 controlreply(spewto
, "G-Lines would hit %d channels. Limit is %d. Not setting G-Lines.", channels
, MAXUSERGLINECHANNELHITS
);
201 } else if (users
> MAXUSERGLINEUSERHITS
) {
202 controlreply(spewto
, "G-Lines would hit %d users. Limit is %d. Not setting G-Lines.", users
, MAXUSERGLINEUSERHITS
);
209 if (!overridesanity
) {
210 /* Remove glines that fail the sanity check */
211 for (gl
= gbuf
->glines
; gl
; gl
= gl
->next
) {
212 if (!isglinesane(gl
, &hint
)) {
213 controlreply(spewto
, "Sanity check failed for G-Line on '%s' - Skipping: %s",
214 glinetostring(gl
), hint
);
223 void glinebufspew(glinebuf
*gbuf
, nick
*spewto
) {
226 char timebuf
[30], lastmod
[30];
228 if (!gbuf
->hitsvalid
)
229 glinebufcounthits(gbuf
, NULL
, NULL
);
232 controlreply(spewto
, "Uncommitted G-Line transaction.");
234 controlreply(spewto
, "G-Line transaction ID %d", gbuf
->id
);
236 controlreply(spewto
, "Comment: %s", (gbuf
->comment
) ? gbuf
->comment
->content
: "(no comment)");
239 strftime(timebuf
, sizeof(timebuf
), "%d/%m/%y %H:%M:%S", localtime(&gbuf
->commit
));
240 controlreply(spewto
, "Committed at: %s", timebuf
);
244 strftime(timebuf
, sizeof(timebuf
), "%d/%m/%y %H:%M:%S", localtime(&gbuf
->amend
));
245 controlreply(spewto
, "Amended at: %s", timebuf
);
248 controlreply(spewto
, "Mask Expiry Last modified Creator Reason");
250 for (gl
= gbuf
->glines
; gl
; gl
= gl
->next
) {
251 strftime(timebuf
, sizeof(timebuf
), "%d/%m/%y %H:%M:%S", localtime(&gl
->expire
));
253 if (gl
->lastmod
== 0)
254 strncpy(lastmod
, "<ulined>", sizeof(lastmod
));
256 strftime(lastmod
, sizeof(lastmod
), "%d/%m/%y %H:%M:%S", localtime(&gl
->lastmod
));
258 controlreply(spewto
, "%-40s %-20s %-20s %-25s %s", glinetostring(gl
), timebuf
, lastmod
, gl
->creator
->content
, gl
->reason
? gl
->reason
->content
: "");
261 controlreply(spewto
, "Hits");
263 for (i
= 0; i
< gbuf
->hits
.cursi
; i
++) {
264 controlreply(spewto
, "%s", ((sstring
**)gbuf
->hits
.content
)[i
]->content
);
267 controlreply(spewto
, "More than 500 hits, list truncated.");
273 controlreply(spewto
, "(no hits)");
276 void glinebufmerge(glinebuf
*gbuf
) {
277 /* TODO: reimplement */
281 /-* Check if an existing gline supercedes this mask *-/
282 for (sgl = gbuf->glines; sgl; sgl = sgl->next) {
283 if (gline_match_mask(sgl, gl)) {
289 /-* Remove older glines this gline matches *-/
290 for (pnext = &gbuf->glines; *pnext; pnext = &((*pnext)->next)) {
293 if (gline_match_mask(gl, sgl)) {
305 int glinebufcommit(glinebuf
*gbuf
, int propagate
) {
306 gline
*gl
, *next
, *sgl
;
307 int users
, channels
, id
;
310 glinebufcounthits(gbuf
, &users
, &channels
);
312 if (propagate
&& (users
> MAXGLINEUSERHITS
|| channels
> MAXGLINECHANNELHITS
)) {
313 controlwall(NO_OPER
, NL_GLINES_AUTO
, "G-Line buffer would hit %d users/%d channels. Not setting G-Lines.");
318 /* Record the commit time */
321 id
= glinebufwritelog(gbuf
, propagate
);
323 /* Move glines to the global gline list */
324 for (gl
= gbuf
->glines
; gl
; gl
= next
) {
327 sgl
= findgline(glinetostring(gl
));
331 * in 1.4, can update expire, reason etc
332 * in 1.3 can only activate/deactivate an existing gline */
334 if (gl
->flags
& GLINE_ACTIVE
&& !(sgl
->flags
& GLINE_ACTIVE
))
335 gline_activate(sgl
, 0, 0);
336 else if (!(gl
->flags
& GLINE_ACTIVE
) && sgl
->flags
& GLINE_ACTIVE
)
337 gline_deactivate(sgl
, 0, 0);
339 #if SNIRCD_VERSION >= 140
340 sgl
->expire
= gl
->expire
;
342 if (gl
->lifetime
> sgl
->lifetime
)
343 sgl
->lifetime
= gl
->lifetime
;
345 freesstring(sgl
->reason
);
346 sgl
->reason
= getsstring(gl
->reason
, 512);
352 gl
->next
= glinelist
;
362 /* We've moved all glines to the global gline list. Clear glines link in the glinebuf. */
370 void glinebufabort(glinebuf
*gbuf
) {
374 for (gl
= gbuf
->glines
; gl
; gl
= next
) {
380 freesstring(gbuf
->comment
);
382 for (i
= 0; i
< gbuf
->hits
.cursi
; i
++)
383 freesstring(((sstring
**)gbuf
->hits
.content
)[i
]);
385 array_free(&gbuf
->hits
);
388 int glinebufundo(int id
) {
393 for (i
= 0; i
< MAXGLINELOG
; i
++) {
394 gbl
= glinebuflog
[i
];
396 if (!gbl
|| gbl
->id
!= id
)
399 for (gl
= gbl
->glines
; gl
; gl
= gl
->next
) {
400 sgl
= findgline(glinetostring(gl
));
407 gline_deactivate(sgl
, 0, 1);
411 glinebuflog
[i
] = NULL
;
419 void glinebufcommentf(glinebuf
*gbuf
, const char *format
, ...) {
423 va_start(va
, format
);
424 vsnprintf(comment
, 511, format
, va
);
428 gbuf
->comment
= getsstring(comment
, 512);
431 void glinebufcommentv(glinebuf
*gbuf
, const char *prefix
, int cargc
, char **cargv
) {
436 strncpy(comment
, prefix
, sizeof(comment
));
440 for (i
= 0; i
< cargc
; i
++) {
442 strncat(comment
, " ", sizeof(comment
));
444 strncat(comment
, cargv
[i
], sizeof(comment
));
449 gbuf
->comment
= getsstring(comment
, 512);
452 int glinebufwritelog(glinebuf
*gbuf
, int propagating
) {
458 return 0; /* Don't waste log IDs on empty gline buffers */
462 /* Find an existing log buffer with the same id */
464 for (i
= 0; i
< MAXGLINELOG
; i
++) {
468 if (glinebuflog
[i
]->id
== gbuf
->id
) {
469 gbl
= glinebuflog
[i
];
470 gbl
->amend
= gbuf
->commit
;
472 /* We're going to re-insert this glinebuf, so remove it for now */
473 glinebuflog
[i
] = NULL
;
480 /* Find a recent glinebuf that's a close match */
481 if (!gbl
&& !propagating
) {
482 for (i
= 0; i
< MAXGLINELOG
; i
++) {
486 if (glinebuflog
[i
]->commit
< getnettime() - 5 && glinebuflog
[i
]->amend
< getnettime() - 5)
489 assert(glinebuflog
[i
]->glines
);
491 if (strcmp(glinebuflog
[i
]->glines
->creator
->content
, gbuf
->glines
->creator
->content
) != 0)
494 gbl
= glinebuflog
[i
];
495 gbl
->amend
= gbuf
->commit
;
497 /* We're going to re-insert this glinebuf, so remove it for now */
498 glinebuflog
[i
] = NULL
;
504 /* Make a new glinebuf for the log */
506 gbl
= malloc(sizeof(glinebuf
));
507 glinebufinit(gbl
, (gbuf
->id
== 0) ? nextglinebufid
++ : gbuf
->id
);
509 assert(gbl
->hitsvalid
);
512 glinebufcommentf(gbl
, "%s", gbuf
->comment
->content
);
513 else if (!propagating
)
514 glinebufcommentf(gbl
, "G-Lines set by %s", gbuf
->glines
->creator
->content
);
516 gbl
->commit
= gbuf
->commit
;
519 /* Save a duplicate of the glines in the log buffer */
520 for (gl
= gbuf
->glines
; gl
; gl
= gl
->next
) {
522 sgl
->next
= gbl
->glines
;
526 gbl
->userhits
+= gbuf
->userhits
;
527 gbl
->channelhits
+= gbuf
->channelhits
;
529 assert(gbuf
->userhits
+ gbuf
->channelhits
== gbuf
->hits
.cursi
);
531 for (i
= 0; i
< gbuf
->hits
.cursi
; i
++) {
532 slot
= array_getfreeslot(&gbl
->hits
);
533 ((sstring
**)gbl
->hits
.content
)[slot
] = getsstring(((sstring
**)gbuf
->hits
.content
)[i
]->content
, 512);
536 /* Log the transaction */
539 if (glinebuflogoffset
>= MAXGLINELOG
)
540 glinebuflogoffset
= 0;
542 if (glinebuflog
[glinebuflogoffset
])
543 glinebufabort(glinebuflog
[glinebuflogoffset
]);
545 glinebuflog
[glinebuflogoffset
] = gbl
;