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