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