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