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