]>
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
, trusts_cidr2str(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
->p_ipaddr
, 128, flags
, creator
, reason
, expire
, lastmod
, lifetime
);
97 void glinebufcounthits(glinebuf
*gbuf
, int *users
, int *channels
) {
105 #if 0 /* Let's just do a new hit check anyway. */
111 gbuf
->channelhits
= 0;
113 for (i
= 0; i
< gbuf
->hits
.cursi
; i
++)
114 freesstring(((sstring
**)gbuf
->hits
.content
)[i
]);
116 array_free(&gbuf
->hits
);
117 array_init(&gbuf
->hits
, sizeof(sstring
*));
119 for (i
= 0; i
<CHANNELHASHSIZE
; i
++) {
120 for (cip
= chantable
[i
]; cip
; cip
= cip
->next
) {
128 for (gl
= gbuf
->glines
; gl
; gl
= gl
->next
) {
129 if (gline_match_channel(gl
, cp
)) {
136 snprintf(uhmask
, sizeof(uhmask
), "channel: %s", cip
->name
->content
);
140 slot
= array_getfreeslot(&gbuf
->hits
);
141 ((sstring
**)gbuf
->hits
.content
)[slot
] = getsstring(uhmask
, 512);
146 for (i
= 0; i
< NICKHASHSIZE
; i
++) {
147 for (np
= nicktable
[i
]; np
; np
= np
->next
) {
150 for (gl
= gbuf
->glines
; gl
; gl
= gl
->next
) {
151 if (gline_match_nick(gl
, np
)) {
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
);
163 slot
= array_getfreeslot(&gbuf
->hits
);
164 ((sstring
**)gbuf
->hits
.content
)[slot
] = getsstring(uhmask
, 512);
172 *users
= gbuf
->userhits
;
175 *channels
= gbuf
->channelhits
;
178 int glinebufchecksane(glinebuf
*gbuf
, nick
*spewto
, int overridesanity
, int overridelimit
) {
180 int users
, channels
, good
;
183 glinebufcounthits(gbuf
, &users
, &channels
);
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
);
189 } else if (users
> MAXUSERGLINEUSERHITS
) {
190 controlreply(spewto
, "G-Lines would hit %d users. Limit is %d. Not setting G-Lines.", users
, MAXUSERGLINEUSERHITS
);
197 if (!overridesanity
) {
198 /* Remove glines that fail the sanity check */
199 for (gl
= gbuf
->glines
; gl
; gl
= gl
->next
) {
200 if (!isglinesane(gl
, &hint
)) {
201 controlreply(spewto
, "Sanity check failed for G-Line on '%s' - Skipping: %s",
202 glinetostring(gl
), hint
);
211 void glinebufspew(glinebuf
*gbuf
, nick
*spewto
) {
214 char timebuf
[30], lastmod
[30];
216 if (!gbuf
->hitsvalid
)
217 glinebufcounthits(gbuf
, NULL
, NULL
);
220 controlreply(spewto
, "Uncommitted G-Line transaction.");
222 controlreply(spewto
, "G-Line transaction ID %d", gbuf
->id
);
224 controlreply(spewto
, "Comment: %s", (gbuf
->comment
) ? gbuf
->comment
->content
: "(no comment)");
227 strftime(timebuf
, sizeof(timebuf
), "%d/%m/%y %H:%M:%S", localtime(&gbuf
->commit
));
228 controlreply(spewto
, "Committed at: %s", timebuf
);
232 strftime(timebuf
, sizeof(timebuf
), "%d/%m/%y %H:%M:%S", localtime(&gbuf
->amend
));
233 controlreply(spewto
, "Amended at: %s", timebuf
);
236 controlreply(spewto
, "Mask Expiry Last modified Creator Reason");
238 for (gl
= gbuf
->glines
; gl
; gl
= gl
->next
) {
239 strftime(timebuf
, sizeof(timebuf
), "%d/%m/%y %H:%M:%S", localtime(&gl
->expire
));
241 if (gl
->lastmod
== 0)
242 strncpy(lastmod
, "<ulined>", sizeof(lastmod
));
244 strftime(lastmod
, sizeof(lastmod
), "%d/%m/%y %H:%M:%S", localtime(&gl
->lastmod
));
246 controlreply(spewto
, "%-40s %-20s %-20s %-25s %s", glinetostring(gl
), timebuf
, lastmod
, gl
->creator
->content
, gl
->reason
? gl
->reason
->content
: "");
249 controlreply(spewto
, "Hits");
251 for (i
= 0; i
< gbuf
->hits
.cursi
; i
++) {
252 controlreply(spewto
, "%s", ((sstring
**)gbuf
->hits
.content
)[i
]->content
);
255 controlreply(spewto
, "More than 500 hits, list truncated.");
261 controlreply(spewto
, "(no hits)");
264 void glinebufmerge(glinebuf
*gbuf
) {
265 /* TODO: reimplement */
269 /-* Check if an existing gline supercedes this mask *-/
270 for (sgl = gbuf->glines; sgl; sgl = sgl->next) {
271 if (gline_match_mask(sgl, gl)) {
277 /-* Remove older glines this gline matches *-/
278 for (pnext = &gbuf->glines; *pnext; pnext = &((*pnext)->next)) {
281 if (gline_match_mask(gl, sgl)) {
293 int glinebufcommit(glinebuf
*gbuf
, int propagate
) {
294 gline
*gl
, *next
, *sgl
;
295 int users
, channels
, id
;
298 glinebufcounthits(gbuf
, &users
, &channels
);
300 if (propagate
&& (users
> MAXGLINEUSERHITS
|| channels
> MAXGLINECHANNELHITS
)) {
301 controlwall(NO_OPER
, NL_GLINES_AUTO
, "G-Line buffer would hit %d users/%d channels. Not setting G-Lines.");
306 /* Record the commit time */
309 id
= glinebufwritelog(gbuf
, propagate
);
311 /* Move glines to the global gline list */
312 for (gl
= gbuf
->glines
; gl
; gl
= next
) {
315 sgl
= findgline(glinetostring(gl
));
319 * in 1.4, can update expire, reason etc
320 * in 1.3 can only activate/deactivate an existing gline */
322 if (gl
->flags
& GLINE_ACTIVE
&& !(sgl
->flags
& GLINE_ACTIVE
))
323 gline_activate(sgl
, 0, 0);
324 else if (!(gl
->flags
& GLINE_ACTIVE
) && sgl
->flags
& GLINE_ACTIVE
)
325 gline_deactivate(sgl
, 0, 0);
327 #if SNIRCD_VERSION >= 140
328 sgl
->expire
= gl
->expire
;
330 if (gl
->lifetime
> sgl
->lifetime
)
331 sgl
->lifetime
= gl
->lifetime
;
333 freesstring(sgl
->reason
);
334 sgl
->reason
= getsstring(gl
->reason
, 512);
340 gl
->next
= glinelist
;
350 /* We've moved all glines to the global gline list. Clear glines link in the glinebuf. */
358 void glinebufabort(glinebuf
*gbuf
) {
362 for (gl
= gbuf
->glines
; gl
; gl
= next
) {
368 freesstring(gbuf
->comment
);
370 for (i
= 0; i
< gbuf
->hits
.cursi
; i
++)
371 freesstring(((sstring
**)gbuf
->hits
.content
)[i
]);
373 array_free(&gbuf
->hits
);
376 int glinebufundo(int id
) {
381 for (i
= 0; i
< MAXGLINELOG
; i
++) {
382 gbl
= glinebuflog
[i
];
384 if (!gbl
|| gbl
->id
!= id
)
387 for (gl
= gbl
->glines
; gl
; gl
= gl
->next
) {
388 sgl
= findgline(glinetostring(gl
));
395 gline_deactivate(sgl
, 0, 1);
399 glinebuflog
[i
] = NULL
;
407 void glinebufcommentf(glinebuf
*gbuf
, const char *format
, ...) {
411 va_start(va
, format
);
412 vsnprintf(comment
, 511, format
, va
);
416 gbuf
->comment
= getsstring(comment
, 512);
419 void glinebufcommentv(glinebuf
*gbuf
, const char *prefix
, int cargc
, char **cargv
) {
424 strncpy(comment
, prefix
, sizeof(comment
));
428 for (i
= 0; i
< cargc
; i
++) {
430 strncat(comment
, " ", sizeof(comment
));
432 strncat(comment
, cargv
[i
], sizeof(comment
));
437 gbuf
->comment
= getsstring(comment
, 512);
440 int glinebufwritelog(glinebuf
*gbuf
, int propagating
) {
446 return 0; /* Don't waste log IDs on empty gline buffers */
450 /* Find an existing log buffer with the same id */
452 for (i
= 0; i
< MAXGLINELOG
; i
++) {
456 if (glinebuflog
[i
]->id
== gbuf
->id
) {
457 gbl
= glinebuflog
[i
];
458 gbl
->amend
= gbuf
->commit
;
460 /* We're going to re-insert this glinebuf, so remove it for now */
461 glinebuflog
[i
] = NULL
;
468 /* Find a recent glinebuf that's a close match */
469 if (!gbl
&& !propagating
) {
470 for (i
= 0; i
< MAXGLINELOG
; i
++) {
474 if (glinebuflog
[i
]->commit
< getnettime() - 5 && glinebuflog
[i
]->amend
< getnettime() - 5)
477 assert(glinebuflog
[i
]->glines
);
479 if (strcmp(glinebuflog
[i
]->glines
->creator
->content
, gbuf
->glines
->creator
->content
) != 0)
482 gbl
= glinebuflog
[i
];
483 gbl
->amend
= gbuf
->commit
;
485 /* We're going to re-insert this glinebuf, so remove it for now */
486 glinebuflog
[i
] = NULL
;
492 /* Make a new glinebuf for the log */
493 if (!gbl
&& gbuf
->id
== 0) {
494 gbl
= malloc(sizeof(glinebuf
));
495 glinebufinit(gbl
, (gbuf
->id
== 0) ? nextglinebufid
++ : gbuf
->id
);
497 assert(gbl
->hitsvalid
);
500 glinebufcommentf(gbl
, "%s", gbuf
->comment
->content
);
501 else if (!propagating
)
502 glinebufcommentf(gbl
, "G-Lines set by %s", gbuf
->glines
->creator
->content
);
504 gbl
->commit
= gbuf
->commit
;
507 /* Save a duplicate of the glines in the log buffer */
508 for (gl
= gbuf
->glines
; gl
; gl
= gl
->next
) {
510 sgl
->next
= gbl
->glines
;
514 gbl
->userhits
+= gbuf
->userhits
;
515 gbl
->channelhits
+= gbuf
->channelhits
;
517 assert(gbuf
->userhits
+ gbuf
->channelhits
== gbuf
->hits
.cursi
);
519 for (i
= 0; i
< gbuf
->hits
.cursi
; i
++) {
520 slot
= array_getfreeslot(&gbl
->hits
);
521 ((sstring
**)gbl
->hits
.content
)[slot
] = getsstring(((sstring
**)gbuf
->hits
.content
)[i
]->content
, 512);
524 /* Log the transaction */
527 if (glinebuflogoffset
>= MAXGLINELOG
)
528 glinebuflogoffset
= 0;
530 if (glinebuflog
[glinebuflogoffset
])
531 glinebufabort(glinebuflog
[glinebuflogoffset
]);
533 glinebuflog
[glinebuflogoffset
] = gbl
;