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