]> jfr.im git - irc/quakenet/newserv.git/blame_incremental - trusts/trusts_db.c
Make sure we only print a TH once in trustlist.
[irc/quakenet/newserv.git] / trusts / trusts_db.c
... / ...
CommitLineData
1#include <stdio.h>
2#include <stdarg.h>
3#include "../dbapi2/dbapi2.h"
4#include "../core/error.h"
5#include "../core/hooks.h"
6#include "../core/schedule.h"
7#include "../control/control.h"
8#include "trusts.h"
9
10DBAPIConn *trustsdb;
11static int tgmaxid, thmaxid;
12static int loaderror;
13static void *flushschedule;
14
15void createtrusttables(int migration);
16void trusts_flush(void (*)(trusthost *), void (*)(trustgroup *));
17void trusts_freeall(void);
18static void th_dbupdatecounts(trusthost *th);
19static void tg_dbupdatecounts(trustgroup *tg);
20
21void createtrusttables(int mode) {
22 char *groups, *hosts;
23
24 if(mode == TABLES_MIGRATION) {
25 groups = "migration_groups";
26 hosts = "migration_hosts";
27 } else if(mode == TABLES_REPLICATION) {
28 groups = "replication_groups";
29 hosts = "replication_hosts";
30 } else {
31 groups = "groups";
32 hosts = "hosts";
33 }
34
35 trustsdb->createtable(trustsdb, NULL, NULL,
36 "CREATE TABLE ? (id INT PRIMARY KEY, name VARCHAR(?), trustedfor INT, mode INT, maxperident INT, maxusage INT, expires INT, lastseen INT, lastmaxusereset INT, createdby VARCHAR(?), contact VARCHAR(?), comment VARCHAR(?))",
37 "Tdddd", groups, TRUSTNAMELEN, CREATEDBYLEN, CONTACTLEN, COMMENTLEN
38 );
39
40 /* I'd like multiple keys here but that's not gonna happen on a cross-database platform :( */
41 trustsdb->createtable(trustsdb, NULL, NULL, "CREATE TABLE ? (id INT PRIMARY KEY, groupid INT, host VARCHAR(?), maxusage INT, created INT, lastseen INT, maxpernode INT, nodebits INT)", "Td", hosts, TRUSTHOSTLEN);
42
43 trustsdb->createtable(trustsdb, NULL, NULL,
44 "CREATE TABLE ? (id INT PRIMARY KEY, groupid INT, groupname VARCHAR(?), ts INT, username VARCHAR(?), message VARCHAR(?))",
45 "Tddd", "log", TRUSTNAMELEN, CREATEDBYLEN, TRUSTLOGLEN
46 );
47}
48
49static void flushdatabase(void *arg) {
50 trusts_flush(th_dbupdatecounts, tg_dbupdatecounts);
51}
52
53static void triggerdbloaded(void *arg) {
54 triggerhook(HOOK_TRUSTS_DB_LOADED, NULL);
55}
56
57static void loadcomplete(void) {
58 /* error has already been shown */
59 if(loaderror)
60 return;
61
62 th_linktree();
63 trustsdbloaded = 1;
64 flushschedule = schedulerecurring(time(NULL) + 300, 0, 300, flushdatabase, NULL);
65
66 scheduleoneshot(time(NULL), triggerdbloaded, NULL);
67}
68
69static void loadhosts_data(const DBAPIResult *result, void *tag) {
70 if(!result) {
71 loaderror = 1;
72 return;
73 }
74
75 if(!result->success) {
76 Error("trusts", ERR_ERROR, "Error loading hosts table.");
77 loaderror = 1;
78
79 result->clear(result);
80 return;
81 }
82
83 if(result->fields != 8) {
84 Error("trusts", ERR_ERROR, "Wrong number of fields in hosts table.");
85 loaderror = 1;
86
87 result->clear(result);
88 return;
89 }
90
91 while(result->next(result)) {
92 unsigned int groupid;
93 trusthost th;
94 char *host;
95
96 th.id = strtoul(result->get(result, 0), NULL, 10);
97 if(th.id > thmaxid)
98 thmaxid = th.id;
99
100 groupid = strtoul(result->get(result, 1), NULL, 10);
101
102 th.group = tg_getbyid(groupid);
103 if(!th.group) {
104 Error("trusts", ERR_WARNING, "Orphaned trust group host: %d", groupid);
105 continue;
106 }
107
108 host = result->get(result, 2);
109 if(!ipmask_parse(host, &th.ip, &th.bits)) {
110 Error("trusts", ERR_WARNING, "Error parsing cidr for host: %s", host);
111 continue;
112 }
113
114 th.maxusage = strtoul(result->get(result, 3), NULL, 10);
115 th.created = (time_t)strtoul(result->get(result, 4), NULL, 10);
116 th.lastseen = (time_t)strtoul(result->get(result, 5), NULL, 10);
117 th.maxpernode = strtol(result->get(result, 6), NULL, 10);
118 th.nodebits = strtol(result->get(result, 7), NULL, 10);
119
120 if(!th_add(&th))
121 Error("trusts", ERR_WARNING, "Error adding host to trust %d: %s", groupid, host);
122 }
123
124 result->clear(result);
125
126 loadcomplete();
127}
128
129static void loadhosts_fini(const DBAPIResult *result, void *tag) {
130 Error("trusts", ERR_INFO, "Finished loading hosts, maximum id: %d", thmaxid);
131}
132
133static void loadgroups_data(const DBAPIResult *result, void *tag) {
134 if(!result) {
135 loaderror = 1;
136 return;
137 }
138
139 if(!result->success) {
140 Error("trusts", ERR_ERROR, "Error loading group table.");
141 loaderror = 1;
142
143 result->clear(result);
144 return;
145 }
146
147 if(result->fields != 12) {
148 Error("trusts", ERR_ERROR, "Wrong number of fields in groups table.");
149 loaderror = 1;
150
151 result->clear(result);
152 return;
153 }
154
155 while(result->next(result)) {
156 trustgroup tg;
157
158 tg.id = strtoul(result->get(result, 0), NULL, 10);
159 if(tg.id > tgmaxid)
160 tgmaxid = tg.id;
161
162 tg.name = getsstring(rtrim(result->get(result, 1)), TRUSTNAMELEN);
163 tg.trustedfor = strtoul(result->get(result, 2), NULL, 10);
164 tg.mode = atoi(result->get(result, 3));
165 tg.maxperident = strtoul(result->get(result, 4), NULL, 10);
166 tg.maxusage = strtoul(result->get(result, 5), NULL, 10);
167 tg.expires = (time_t)strtoul(result->get(result, 6), NULL, 10);
168 tg.lastseen = (time_t)strtoul(result->get(result, 7), NULL, 10);
169 tg.lastmaxusereset = (time_t)strtoul(result->get(result, 8), NULL, 10);
170 tg.createdby = getsstring(rtrim(result->get(result, 9)), CREATEDBYLEN);
171 tg.contact = getsstring(rtrim(result->get(result, 10)), CONTACTLEN);
172 tg.comment = getsstring(rtrim(result->get(result, 11)), COMMENTLEN);
173
174 if(tg.name && tg.createdby && tg.contact && tg.comment) {
175 if(!tg_add(&tg))
176 Error("trusts", ERR_WARNING, "Error adding trustgroup %d: %s", tg.id, tg.name->content);
177 } else {
178 Error("trusts", ERR_ERROR, "Error allocating sstring in group loader, id: %d", tg.id);
179 }
180
181 freesstring(tg.name);
182 freesstring(tg.createdby);
183 freesstring(tg.contact);
184 freesstring(tg.comment);
185 }
186
187 result->clear(result);
188}
189
190static void loadgroups_fini(const DBAPIResult *result, void *tag) {
191 Error("trusts", ERR_INFO, "Finished loading groups, maximum id: %d.", tgmaxid);
192}
193
194static int trusts_connectdb(void) {
195 if(!trustsdb) {
196 trustsdb = dbapi2open(NULL, "trusts");
197 if(!trustsdb) {
198 Error("trusts", ERR_WARNING, "Unable to connect to db -- not loaded.");
199 return 0;
200 }
201 }
202
203 createtrusttables(TABLES_REGULAR);
204
205 return 1;
206}
207
208int trusts_loaddb(void) {
209 if(!trusts_connectdb())
210 return 0;
211
212 loaderror = 0;
213
214 trustsdb->loadtable(trustsdb, NULL, loadgroups_data, loadgroups_fini, NULL, "groups");
215 trustsdb->loadtable(trustsdb, NULL, loadhosts_data, loadhosts_fini, NULL, "hosts");
216
217 return 1;
218}
219
220void trusts_closedb(int closeconnection) {
221 if(!trustsdb)
222 return;
223
224 if(flushschedule) {
225 deleteschedule(flushschedule, flushdatabase, NULL);
226 flushschedule = NULL;
227
228 flushdatabase(NULL);
229 }
230
231 trusts_freeall();
232
233 trustsdbloaded = 0;
234 thmaxid = tgmaxid = 0;
235
236 if(closeconnection) {
237 trustsdb->close(trustsdb);
238 trustsdb = NULL;
239 }
240
241 triggerhook(HOOK_TRUSTS_DB_CLOSED, NULL);
242}
243
244static void th_dbupdatecounts(trusthost *th) {
245 trustsdb->squery(trustsdb, "UPDATE ? SET lastseen = ?, maxusage = ? WHERE id = ?", "Ttuu", "hosts", th->lastseen, th->maxusage, th->id);
246}
247
248static void tg_dbupdatecounts(trustgroup *tg) {
249 trustsdb->squery(trustsdb, "UPDATE ? SET lastseen = ?, maxusage = ? WHERE id = ?", "Ttuu", "groups", tg->lastseen, tg->maxusage, tg->id);
250}
251
252trusthost *th_copy(trusthost *ith) {
253 trusthost *th, *superset, *subset;
254
255 th = th_add(ith);
256 if(!th)
257 return NULL;
258
259 trustsdb_insertth("hosts", th, th->group->id);
260
261 th_getsuperandsubsets(&ith->ip, ith->bits, &superset, &subset);
262 th_adjusthosts(th, superset, subset);
263 th_linktree();
264
265 return th;
266}
267
268trusthost *th_new(trustgroup *tg, char *host) {
269 trusthost *th, nth;
270
271 if(!ipmask_parse(host, &nth.ip, &nth.bits))
272 return NULL;
273
274 nth.group = tg;
275 nth.id = thmaxid + 1;
276 nth.created = time(NULL);
277 nth.lastseen = 0;
278 nth.maxusage = 0;
279
280 nth.maxpernode = 0;
281 nth.nodebits = (irc_in_addr_is_ipv4(&nth.ip))?128:64;
282
283 th = th_copy(&nth);
284 if(!th)
285 return NULL;
286
287 thmaxid++;
288
289 return th;
290}
291
292trustgroup *tg_copy(trustgroup *itg) {
293 trustgroup *tg = tg_add(itg);
294 if(!tg)
295 return NULL;
296
297 trustsdb_inserttg("groups", tg);
298 return tg;
299}
300
301trustgroup *tg_new(trustgroup *itg) {
302 trustgroup *tg;
303
304 itg->id = tgmaxid + 1;
305 itg->maxusage = 0;
306 itg->lastseen = 0;
307 itg->lastmaxusereset = 0;
308
309 tg = tg_copy(itg);
310 if(!tg)
311 return NULL;
312
313 tgmaxid++;
314
315 return tg;
316}
317
318void trustsdb_insertth(char *table, trusthost *th, unsigned int groupid) {
319 trustsdb->squery(trustsdb,
320 "INSERT INTO ? (id, groupid, host, maxusage, created, lastseen, maxpernode, nodebits) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
321 "Tuusuutuu", table, th->id, groupid, trusts_cidr2str(&th->ip, th->bits), th->maxusage, th->created, th->lastseen, th->maxpernode, th->nodebits
322 );
323}
324
325void trustsdb_inserttg(char *table, trustgroup *tg) {
326 trustsdb->squery(trustsdb,
327 "INSERT INTO ? (id, name, trustedfor, mode, maxperident, maxusage, expires, lastseen, lastmaxusereset, createdby, contact, comment) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
328 "Tusuuuutttsss", table, tg->id, tg->name->content, tg->trustedfor, tg->mode, tg->maxperident, tg->maxusage, tg->expires, tg->lastseen, tg->lastmaxusereset, tg->createdby->content, tg->contact->content, tg->comment->content
329 );
330}
331
332void tg_update(trustgroup *tg) {
333 trustsdb->squery(trustsdb,
334 "UPDATE ? SET name = ?, trustedfor = ?, maxperident = ?, maxusage = ?, expires = ?, lastseen = ?, lastmaxusereset = ?, createdby = ?, contact = ?, comment = ? WHERE id = ?",
335 "Tsuuuutttsssu", "groups", tg->name->content, tg->trustedfor, tg->mode, tg->maxperident, tg->maxusage, tg->expires, tg->lastseen, tg->lastmaxusereset, tg->createdby->content, tg->contact->content, tg->comment->content, tg->id
336 );
337}
338
339void trustsdb_deletetg(char *table, trustgroup *tg) {
340 trustsdb->squery(trustsdb,
341 "DELETE FROM ? WHERE id = ?",
342 "Tu", "groups", tg->id);
343}
344
345void tg_delete(trustgroup *tg) {
346 trustgroup **pnext;
347
348 for(pnext=&tglist;*pnext;pnext=&((*pnext)->next)) {
349 if(*pnext == tg) {
350 *pnext = tg->next;
351 break;
352 }
353 }
354
355 trustsdb_deletetg("groups", tg);
356 tg_free(tg, 1);
357}
358
359void trustsdb_deleteth(char *table, trusthost *th) {
360 trustsdb->squery(trustsdb,
361 "DELETE FROM ? WHERE id = ?",
362 "Tu", "hosts", th->id);
363}
364
365void th_delete(trusthost *th) {
366 trusthost **pnext;
367 nick *np;
368
369 for(pnext=&(th->group->hosts);*pnext;pnext=&((*pnext)->next)) {
370 if(*pnext == th) {
371 *pnext = th->next;
372 break;
373 }
374 }
375
376 if(th->parent) {
377 for(pnext=&(th->parent->children);*pnext;pnext=&((*pnext)->nextbychild)) {
378 if(*pnext == th) {
379 *pnext = th->nextbychild;
380 break;
381 }
382 }
383 }
384
385 for(np=th->users;np;np=nextbytrust(np))
386 settrusthost(np, NULL);
387
388 th->group->count -= th->count;
389
390 trustsdb_deleteth("hosts", th);
391 th_free(th);
392
393 th_linktree();
394}
395
396void trustlog(trustgroup *tg, const char *user, const char *format, ...) {
397 char buf[TRUSTLOGLEN+1];
398 va_list va;
399 unsigned int now;
400
401 va_start(va, format);
402 vsnprintf(buf, sizeof(buf), format, va);
403 va_end(va);
404
405 now = time(NULL);
406
407 trustsdb->squery(trustsdb,
408 "INSERT INTO ? (ts, groupid, groupname, username, message) VALUES (?, ?, ?, ?, ?)",
409 "Tuusss", "log", now, tg->id, tg->name->content, user, buf);
410}
411
412static void trustlogquery_callback(const struct DBAPIResult *result, void *arg) {
413 nick *np = (nick *)arg;
414 int rows = 0;
415
416 if(!result || !result->success) {
417 controlreply(np, "Error querying the log.");
418
419 if(result)
420 result->clear(result);
421
422 return;
423 }
424
425 if(result->fields != 5) {
426 Error("trusts", ERR_ERROR, "Wrong number of fields in log table.");
427
428 result->clear(result);
429 return;
430 }
431
432 while(result->next(result)) {
433 unsigned int ts, groupid;
434 char *groupname, *user, *message;
435
436 ts = strtoul(result->get(result, 0), NULL, 10);
437 groupid = strtoul(result->get(result, 1), NULL, 10);
438 groupname = result->get(result, 2);
439 user = result->get(result, 3);
440 message = result->get(result, 4);
441
442 controlreply(np, "[%s] #%d/%s (%s) %s", trusts_timetostr(ts), groupid, groupname, user, message);
443 rows++;
444 }
445
446 result->clear(result);
447
448 controlreply(np, "--- Done. Found %d entries.", rows);
449}
450
451void trustlogspewid(nick *np, unsigned int groupid, unsigned int limit) {
452 trustsdb->query(trustsdb, trustlogquery_callback, (void *)np,
453 "SELECT ts, groupid, groupname, username, message FROM ? WHERE groupid = ? ORDER BY ts DESC LIMIT ?",
454 "Tuu", "log", groupid, limit);
455}
456
457void trustlogspewname(nick *np, const char *groupname, unsigned int limit) {
458 trustsdb->query(trustsdb, trustlogquery_callback, (void *)np,
459 "SELECT ts, groupid, groupname, username, message FROM ? WHERE groupname = ? ORDER BY ts DESC LIMIT ?",
460 "Tsu", "log", groupname, limit);
461}
462
463void trustloggrep(nick *np, const char *pattern, unsigned int limit) {
464 char buf[512];
465 snprintf(buf, sizeof(buf), "%%%s%%", pattern);
466
467 trustsdb->query(trustsdb, trustlogquery_callback, (void *)np,
468 "SELECT ts, groupid, groupname, username, message FROM ? WHERE message LIKE ? ORDER BY ts DESC LIMIT ?",
469 "Tsu", "log", buf, limit);
470}
471
472void _init(void) {
473 trusts_connectdb();
474}
475
476void _fini(void) {
477 trusts_closedb(1);
478}