]> jfr.im git - irc/quakenet/newserv.git/blame - trusts/trusts_db.c
Rename trusts_cidr2str to CIDRtostr() and move it to lib/irc_ipv6.c.
[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) {
83bccee3
CP
200 trustsdb = dbapi2open(NULL, "trusts");
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
82a316e7 287 th = th_copy(&nth);
d2c08930
CP
288 if(!th)
289 return NULL;
290
291 thmaxid++;
292
82a316e7
CP
293 return th;
294}
d2c08930 295
82a316e7
CP
296trustgroup *tg_copy(trustgroup *itg) {
297 trustgroup *tg = tg_add(itg);
298 if(!tg)
299 return NULL;
d2c08930 300
82a316e7
CP
301 trustsdb_inserttg("groups", tg);
302 return tg;
d2c08930
CP
303}
304
82a316e7
CP
305trustgroup *tg_new(trustgroup *itg) {
306 trustgroup *tg;
307
308 itg->id = tgmaxid + 1;
309 itg->maxusage = 0;
310 itg->lastseen = 0;
1f685425 311 itg->lastmaxusereset = 0;
82a316e7
CP
312
313 tg = tg_copy(itg);
d2c08930
CP
314 if(!tg)
315 return NULL;
316
317 tgmaxid++;
318
82a316e7
CP
319 return tg;
320}
321
322void trustsdb_insertth(char *table, trusthost *th, unsigned int groupid) {
d2c08930 323 trustsdb->squery(trustsdb,
cebc4cab 324 "INSERT INTO ? (id, groupid, host, maxusage, created, lastseen, maxpernode, nodebits) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
3898f973 325 "Tuusuutuu", table, th->id, groupid, CIDRtostr(th->ip, th->bits), th->maxusage, th->created, th->lastseen, th->maxpernode, th->nodebits
d2c08930 326 );
82a316e7 327}
d2c08930 328
82a316e7
CP
329void trustsdb_inserttg(char *table, trustgroup *tg) {
330 trustsdb->squery(trustsdb,
de723023
GB
331 "INSERT INTO ? (id, name, trustedfor, flags, maxperident, maxusage, expires, lastseen, lastmaxusereset, createdby, contact, comment) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
332 "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 333 );
d2c08930 334}
b9c52ee0 335
2ab0a1e7
CP
336void tg_update(trustgroup *tg) {
337 trustsdb->squery(trustsdb,
e40626f0 338 "UPDATE ? SET name = ?, trustedfor = ?, flags = ?, maxperident = ?, maxusage = ?, expires = ?, lastseen = ?, lastmaxusereset = ?, createdby = ?, contact = ?, comment = ? WHERE id = ?",
de723023 339 "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
340 );
341}
342
06deaa30
GB
343void trustsdb_deletetg(char *table, trustgroup *tg) {
344 trustsdb->squery(trustsdb,
345 "DELETE FROM ? WHERE id = ?",
346 "Tu", "groups", tg->id);
347}
348
2ab0a1e7 349void tg_delete(trustgroup *tg) {
06deaa30
GB
350 trustgroup **pnext;
351
352 for(pnext=&tglist;*pnext;pnext=&((*pnext)->next)) {
353 if(*pnext == tg) {
354 *pnext = tg->next;
355 break;
356 }
357 }
358
359 trustsdb_deletetg("groups", tg);
360 tg_free(tg, 1);
361}
362
c1da06f9
GB
363void th_update(trusthost *th) {
364 trustsdb->squery(trustsdb,
365 "UPDATE ? SET maxpernode = ?, nodebits = ? WHERE id = ?",
366 "Tuuu", "hosts", th->maxpernode, th->nodebits, th->id
367 );
368}
369
06deaa30
GB
370void trustsdb_deleteth(char *table, trusthost *th) {
371 trustsdb->squery(trustsdb,
372 "DELETE FROM ? WHERE id = ?",
373 "Tu", "hosts", th->id);
2ab0a1e7
CP
374}
375
376void th_delete(trusthost *th) {
06deaa30
GB
377 trusthost **pnext;
378 nick *np;
379
380 for(pnext=&(th->group->hosts);*pnext;pnext=&((*pnext)->next)) {
381 if(*pnext == th) {
382 *pnext = th->next;
383 break;
384 }
385 }
386
0a40424a
GB
387 if(th->parent) {
388 for(pnext=&(th->parent->children);*pnext;pnext=&((*pnext)->nextbychild)) {
389 if(*pnext == th) {
390 *pnext = th->nextbychild;
391 break;
392 }
393 }
394 }
395
06deaa30
GB
396 for(np=th->users;np;np=nextbytrust(np))
397 settrusthost(np, NULL);
398
399 th->group->count -= th->count;
400
dad59314
GB
401 if(th->parent) {
402 th->parent->count += th->count;
403
404 if(th->lastseen > th->parent->lastseen)
405 th->parent->lastseen = th->lastseen;
406 }
407
06deaa30
GB
408 trustsdb_deleteth("hosts", th);
409 th_free(th);
34e3de85
GB
410
411 th_linktree();
2ab0a1e7
CP
412}
413
1467e9a4 414void trustlog(trustgroup *tg, const char *user, const char *format, ...) {
01bd21d3
GB
415 char buf[TRUSTLOGLEN+1];
416 va_list va;
417 unsigned int now;
418
419 va_start(va, format);
420 vsnprintf(buf, sizeof(buf), format, va);
421 va_end(va);
422
423 now = time(NULL);
424
425 trustsdb->squery(trustsdb,
1467e9a4
GB
426 "INSERT INTO ? (ts, groupid, groupname, username, message) VALUES (?, ?, ?, ?, ?)",
427 "Tuusss", "log", now, tg->id, tg->name->content, user, buf);
01bd21d3
GB
428}
429
430static void trustlogquery_callback(const struct DBAPIResult *result, void *arg) {
431 nick *np = (nick *)arg;
432 int rows = 0;
433
434 if(!result || !result->success) {
435 controlreply(np, "Error querying the log.");
436
437 if(result)
438 result->clear(result);
439
440 return;
441 }
442
7db61652
GB
443 if(result->fields != 5) {
444 Error("trusts", ERR_ERROR, "Wrong number of fields in log table.");
445
446 result->clear(result);
447 return;
448 }
449
01bd21d3
GB
450 while(result->next(result)) {
451 unsigned int ts, groupid;
1467e9a4 452 char *groupname, *user, *message;
01bd21d3
GB
453
454 ts = strtoul(result->get(result, 0), NULL, 10);
455 groupid = strtoul(result->get(result, 1), NULL, 10);
1467e9a4
GB
456 groupname = result->get(result, 2);
457 user = result->get(result, 3);
458 message = result->get(result, 4);
01bd21d3 459
1467e9a4 460 controlreply(np, "[%s] #%d/%s (%s) %s", trusts_timetostr(ts), groupid, groupname, user, message);
01bd21d3
GB
461 rows++;
462 }
463
7db61652
GB
464 result->clear(result);
465
1467e9a4 466 controlreply(np, "--- Done. Found %d entries.", rows);
01bd21d3
GB
467}
468
1467e9a4 469void trustlogspewid(nick *np, unsigned int groupid, unsigned int limit) {
01bd21d3 470 trustsdb->query(trustsdb, trustlogquery_callback, (void *)np,
1467e9a4 471 "SELECT ts, groupid, groupname, username, message FROM ? WHERE groupid = ? ORDER BY ts DESC LIMIT ?",
01bd21d3
GB
472 "Tuu", "log", groupid, limit);
473}
474
1467e9a4
GB
475void trustlogspewname(nick *np, const char *groupname, unsigned int limit) {
476 trustsdb->query(trustsdb, trustlogquery_callback, (void *)np,
477 "SELECT ts, groupid, groupname, username, message FROM ? WHERE groupname = ? ORDER BY ts DESC LIMIT ?",
478 "Tsu", "log", groupname, limit);
479}
480
01bd21d3
GB
481void trustloggrep(nick *np, const char *pattern, unsigned int limit) {
482 char buf[512];
483 snprintf(buf, sizeof(buf), "%%%s%%", pattern);
484
485 trustsdb->query(trustsdb, trustlogquery_callback, (void *)np,
7db61652 486 "SELECT ts, groupid, groupname, username, message FROM ? WHERE message LIKE ? ORDER BY ts DESC LIMIT ?",
01bd21d3
GB
487 "Tsu", "log", buf, limit);
488}
489
b9c52ee0 490void _init(void) {
82a316e7 491 trusts_connectdb();
b9c52ee0
CP
492}
493
494void _fini(void) {
495 trusts_closedb(1);
496}