]> jfr.im git - irc/quakenet/newserv.git/blame_incremental - trusts/trusts_db.c
Bugfix: Make sure to properly walk upwards in the tree.
[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 "../irc/irc.h"
9#include "trusts.h"
10
11DBAPIConn *trustsdb;
12static int tgmaxid, thmaxid;
13static int loaderror;
14static void *flushschedule;
15
16void createtrusttables(int migration);
17void trusts_flush(void (*)(trusthost *), void (*)(trustgroup *));
18void trusts_freeall(void);
19static void th_dbupdatecounts(trusthost *th);
20static void tg_dbupdatecounts(trustgroup *tg);
21
22void createtrusttables(int mode) {
23 char *groups, *hosts;
24
25 if(mode == TABLES_MIGRATION) {
26 groups = "migration_groups";
27 hosts = "migration_hosts";
28 } else if(mode == TABLES_REPLICATION) {
29 groups = "replication_groups";
30 hosts = "replication_hosts";
31 } else {
32 groups = "groups";
33 hosts = "hosts";
34 }
35
36 trustsdb->createtable(trustsdb, NULL, NULL,
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
39 );
40
41 /* I'd like multiple keys here but that's not gonna happen on a cross-database platform :( */
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);
43
44 trustsdb->createtable(trustsdb, NULL, NULL,
45 "CREATE TABLE ? (id INT PRIMARY KEY, groupid INT, groupname VARCHAR(?), ts INT, username VARCHAR(?), message VARCHAR(?))",
46 "Tddd", "log", TRUSTNAMELEN, CREATEDBYLEN, TRUSTLOGLEN
47 );
48}
49
50static void flushdatabase(void *arg) {
51 trusts_flush(th_dbupdatecounts, tg_dbupdatecounts);
52}
53
54static void triggerdbloaded(void *arg) {
55 triggerhook(HOOK_TRUSTS_DB_LOADED, NULL);
56}
57
58static void loadcomplete(void) {
59 /* error has already been shown */
60 if(loaderror)
61 return;
62
63 th_linktree();
64 trustsdbloaded = 1;
65 flushschedule = schedulerecurring(time(NULL) + 300, 0, 300, flushdatabase, NULL);
66
67 scheduleoneshot(time(NULL), triggerdbloaded, NULL);
68}
69
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
84 if(result->fields != 8) {
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)) {
93 unsigned int groupid;
94 trusthost th;
95 char *host;
96
97 th.id = strtoul(result->get(result, 0), NULL, 10);
98 if(th.id > thmaxid)
99 thmaxid = th.id;
100
101 groupid = strtoul(result->get(result, 1), NULL, 10);
102
103 th.group = tg_getbyid(groupid);
104 if(!th.group) {
105 Error("trusts", ERR_WARNING, "Orphaned trust group host: %d", groupid);
106 continue;
107 }
108
109 host = result->get(result, 2);
110 if(!ipmask_parse(host, &th.ip, &th.bits)) {
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);
116 th.created = (time_t)strtoul(result->get(result, 4), NULL, 10);
117 th.lastseen = (time_t)strtoul(result->get(result, 5), NULL, 10);
118 th.maxpernode = strtol(result->get(result, 6), NULL, 10);
119 th.nodebits = strtol(result->get(result, 7), NULL, 10);
120
121 if(!th_add(&th))
122 Error("trusts", ERR_WARNING, "Error adding host to trust %d: %s", groupid, host);
123 }
124
125 result->clear(result);
126
127 loadcomplete();
128}
129
130static void loadhosts_fini(const DBAPIResult *result, void *tag) {
131 Error("trusts", ERR_INFO, "Finished loading hosts, maximum id: %d", thmaxid);
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)) {
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);
170 tg.lastmaxusereset = (time_t)strtoul(result->get(result, 8), NULL, 10);
171 tg.createdby = getsstring(rtrim(result->get(result, 9)), CREATEDBYLEN);
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);
178 } else {
179 Error("trusts", ERR_ERROR, "Error allocating sstring in group loader, id: %d", tg.id);
180 }
181
182 freesstring(tg.name);
183 freesstring(tg.createdby);
184 freesstring(tg.contact);
185 freesstring(tg.comment);
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);
193}
194
195static int trusts_connectdb(void) {
196 if(!trustsdb) {
197 trustsdb = dbapi2open(NULL, "trusts");
198 if(!trustsdb) {
199 Error("trusts", ERR_WARNING, "Unable to connect to db -- not loaded.");
200 return 0;
201 }
202 }
203
204 createtrusttables(TABLES_REGULAR);
205
206 return 1;
207}
208
209int trusts_loaddb(void) {
210 if(!trusts_connectdb())
211 return 0;
212
213 loaderror = 0;
214
215 trustsdb->loadtable(trustsdb, NULL, loadgroups_data, loadgroups_fini, NULL, "groups");
216 trustsdb->loadtable(trustsdb, NULL, loadhosts_data, loadhosts_fini, NULL, "hosts");
217
218 return 1;
219}
220
221void trusts_closedb(int closeconnection) {
222 if(!trustsdb)
223 return;
224
225 if(flushschedule) {
226 deleteschedule(flushschedule, flushdatabase, NULL);
227 flushschedule = NULL;
228
229 flushdatabase(NULL);
230 }
231
232 trusts_freeall();
233
234 trustsdbloaded = 0;
235 thmaxid = tgmaxid = 0;
236
237 if(closeconnection) {
238 trustsdb->close(trustsdb);
239 trustsdb = NULL;
240 }
241
242 triggerhook(HOOK_TRUSTS_DB_CLOSED, NULL);
243}
244
245static void th_dbupdatecounts(trusthost *th) {
246 trustsdb->squery(trustsdb, "UPDATE ? SET lastseen = ?, maxusage = ? WHERE id = ?", "Ttuu", "hosts", th->lastseen, th->maxusage, th->id);
247}
248
249static void tg_dbupdatecounts(trustgroup *tg) {
250 trustsdb->squery(trustsdb, "UPDATE ? SET lastseen = ?, maxusage = ? WHERE id = ?", "Ttuu", "groups", tg->lastseen, tg->maxusage, tg->id);
251}
252
253trusthost *th_copy(trusthost *ith) {
254 trusthost *th, *superset, *subset;
255
256 th = th_add(ith);
257 if(!th)
258 return NULL;
259
260 trustsdb_insertth("hosts", th, th->group->id);
261
262 th_getsuperandsubsets(&ith->ip, ith->bits, &superset, &subset);
263 th_adjusthosts(th, superset, subset);
264 th_linktree();
265
266 return th;
267}
268
269trusthost *th_new(trustgroup *tg, char *host) {
270 trusthost *th, nth;
271
272 if(!ipmask_parse(host, &nth.ip, &nth.bits))
273 return NULL;
274
275 nth.group = tg;
276 nth.id = thmaxid + 1;
277 nth.created = getnettime();
278 nth.lastseen = 0;
279 nth.maxusage = 0;
280
281 nth.maxpernode = 0;
282 nth.nodebits = (irc_in_addr_is_ipv4(&nth.ip))?128:64;
283
284 th = th_copy(&nth);
285 if(!th)
286 return NULL;
287
288 thmaxid++;
289
290 return th;
291}
292
293trustgroup *tg_copy(trustgroup *itg) {
294 trustgroup *tg = tg_add(itg);
295 if(!tg)
296 return NULL;
297
298 trustsdb_inserttg("groups", tg);
299 return tg;
300}
301
302trustgroup *tg_new(trustgroup *itg) {
303 trustgroup *tg;
304
305 itg->id = tgmaxid + 1;
306 itg->maxusage = 0;
307 itg->lastseen = 0;
308 itg->lastmaxusereset = 0;
309
310 tg = tg_copy(itg);
311 if(!tg)
312 return NULL;
313
314 tgmaxid++;
315
316 return tg;
317}
318
319void trustsdb_insertth(char *table, trusthost *th, unsigned int groupid) {
320 trustsdb->squery(trustsdb,
321 "INSERT INTO ? (id, groupid, host, maxusage, created, lastseen, maxpernode, nodebits) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
322 "Tuusuutuu", table, th->id, groupid, trusts_cidr2str(&th->ip, th->bits), th->maxusage, th->created, th->lastseen, th->maxpernode, th->nodebits
323 );
324}
325
326void trustsdb_inserttg(char *table, trustgroup *tg) {
327 trustsdb->squery(trustsdb,
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
330 );
331}
332
333void tg_update(trustgroup *tg) {
334 trustsdb->squery(trustsdb,
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
337 );
338}
339
340void trustsdb_deletetg(char *table, trustgroup *tg) {
341 trustsdb->squery(trustsdb,
342 "DELETE FROM ? WHERE id = ?",
343 "Tu", "groups", tg->id);
344}
345
346void tg_delete(trustgroup *tg) {
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
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
367void trustsdb_deleteth(char *table, trusthost *th) {
368 trustsdb->squery(trustsdb,
369 "DELETE FROM ? WHERE id = ?",
370 "Tu", "hosts", th->id);
371}
372
373void th_delete(trusthost *th) {
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
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
393 for(np=th->users;np;np=nextbytrust(np))
394 settrusthost(np, NULL);
395
396 th->group->count -= th->count;
397
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
405 trustsdb_deleteth("hosts", th);
406 th_free(th);
407
408 th_linktree();
409}
410
411void trustlog(trustgroup *tg, const char *user, const char *format, ...) {
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,
423 "INSERT INTO ? (ts, groupid, groupname, username, message) VALUES (?, ?, ?, ?, ?)",
424 "Tuusss", "log", now, tg->id, tg->name->content, user, buf);
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
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
447 while(result->next(result)) {
448 unsigned int ts, groupid;
449 char *groupname, *user, *message;
450
451 ts = strtoul(result->get(result, 0), NULL, 10);
452 groupid = strtoul(result->get(result, 1), NULL, 10);
453 groupname = result->get(result, 2);
454 user = result->get(result, 3);
455 message = result->get(result, 4);
456
457 controlreply(np, "[%s] #%d/%s (%s) %s", trusts_timetostr(ts), groupid, groupname, user, message);
458 rows++;
459 }
460
461 result->clear(result);
462
463 controlreply(np, "--- Done. Found %d entries.", rows);
464}
465
466void trustlogspewid(nick *np, unsigned int groupid, unsigned int limit) {
467 trustsdb->query(trustsdb, trustlogquery_callback, (void *)np,
468 "SELECT ts, groupid, groupname, username, message FROM ? WHERE groupid = ? ORDER BY ts DESC LIMIT ?",
469 "Tuu", "log", groupid, limit);
470}
471
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
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,
483 "SELECT ts, groupid, groupname, username, message FROM ? WHERE message LIKE ? ORDER BY ts DESC LIMIT ?",
484 "Tsu", "log", buf, limit);
485}
486
487void _init(void) {
488 trusts_connectdb();
489}
490
491void _fini(void) {
492 trusts_closedb(1);
493}