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