]> jfr.im git - irc/quakenet/newserv.git/blame_incremental - trusts/trusts_db.c
Another query fix.
[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)", "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 trustsdbloaded = 1;
63 flushschedule = schedulerecurring(time(NULL) + 300, 0, 300, flushdatabase, NULL);
64
65 scheduleoneshot(time(NULL), triggerdbloaded, NULL);
66}
67
68static void loadhosts_data(const DBAPIResult *result, void *tag) {
69 if(!result) {
70 loaderror = 1;
71 return;
72 }
73
74 if(!result->success) {
75 Error("trusts", ERR_ERROR, "Error loading hosts table.");
76 loaderror = 1;
77
78 result->clear(result);
79 return;
80 }
81
82 if(result->fields != 6) {
83 Error("trusts", ERR_ERROR, "Wrong number of fields in hosts table.");
84 loaderror = 1;
85
86 result->clear(result);
87 return;
88 }
89
90 while(result->next(result)) {
91 unsigned int groupid;
92 trusthost th;
93 char *host;
94
95 th.id = strtoul(result->get(result, 0), NULL, 10);
96 if(th.id > thmaxid)
97 thmaxid = th.id;
98
99 groupid = strtoul(result->get(result, 1), NULL, 10);
100
101 th.group = tg_getbyid(groupid);
102 if(!th.group) {
103 Error("trusts", ERR_WARNING, "Orphaned trust group host: %d", groupid);
104 continue;
105 }
106
107 host = result->get(result, 2);
108 if(!trusts_str2cidr(host, &th.ip, &th.mask)) {
109 Error("trusts", ERR_WARNING, "Error parsing cidr for host: %s", host);
110 continue;
111 }
112
113 th.maxusage = strtoul(result->get(result, 3), NULL, 10);
114 th.created = (time_t)strtoul(result->get(result, 4), NULL, 10);
115 th.lastseen = (time_t)strtoul(result->get(result, 5), NULL, 10);
116
117 if(!th_add(&th))
118 Error("trusts", ERR_WARNING, "Error adding host to trust %d: %s", groupid, host);
119 }
120
121 result->clear(result);
122
123 loadcomplete();
124}
125
126static void loadhosts_fini(const DBAPIResult *result, void *tag) {
127 Error("trusts", ERR_INFO, "Finished loading hosts, maximum id: %d", thmaxid);
128}
129
130static void loadgroups_data(const DBAPIResult *result, void *tag) {
131 if(!result) {
132 loaderror = 1;
133 return;
134 }
135
136 if(!result->success) {
137 Error("trusts", ERR_ERROR, "Error loading group table.");
138 loaderror = 1;
139
140 result->clear(result);
141 return;
142 }
143
144 if(result->fields != 12) {
145 Error("trusts", ERR_ERROR, "Wrong number of fields in groups table.");
146 loaderror = 1;
147
148 result->clear(result);
149 return;
150 }
151
152 while(result->next(result)) {
153 trustgroup tg;
154
155 tg.id = strtoul(result->get(result, 0), NULL, 10);
156 if(tg.id > tgmaxid)
157 tgmaxid = tg.id;
158
159 tg.name = getsstring(rtrim(result->get(result, 1)), TRUSTNAMELEN);
160 tg.trustedfor = strtoul(result->get(result, 2), NULL, 10);
161 tg.mode = atoi(result->get(result, 3));
162 tg.maxperident = strtoul(result->get(result, 4), NULL, 10);
163 tg.maxusage = strtoul(result->get(result, 5), NULL, 10);
164 tg.expires = (time_t)strtoul(result->get(result, 6), NULL, 10);
165 tg.lastseen = (time_t)strtoul(result->get(result, 7), NULL, 10);
166 tg.lastmaxusereset = (time_t)strtoul(result->get(result, 8), NULL, 10);
167 tg.createdby = getsstring(rtrim(result->get(result, 9)), CREATEDBYLEN);
168 tg.contact = getsstring(rtrim(result->get(result, 10)), CONTACTLEN);
169 tg.comment = getsstring(rtrim(result->get(result, 11)), COMMENTLEN);
170
171 if(tg.name && tg.createdby && tg.contact && tg.comment) {
172 if(!tg_add(&tg))
173 Error("trusts", ERR_WARNING, "Error adding trustgroup %d: %s", tg.id, tg.name->content);
174 } else {
175 Error("trusts", ERR_ERROR, "Error allocating sstring in group loader, id: %d", tg.id);
176 }
177
178 freesstring(tg.name);
179 freesstring(tg.createdby);
180 freesstring(tg.contact);
181 freesstring(tg.comment);
182 }
183
184 result->clear(result);
185}
186
187static void loadgroups_fini(const DBAPIResult *result, void *tag) {
188 Error("trusts", ERR_INFO, "Finished loading groups, maximum id: %d.", tgmaxid);
189}
190
191static int trusts_connectdb(void) {
192 if(!trustsdb) {
193 trustsdb = dbapi2open(NULL, "trusts");
194 if(!trustsdb) {
195 Error("trusts", ERR_WARNING, "Unable to connect to db -- not loaded.");
196 return 0;
197 }
198 }
199
200 createtrusttables(TABLES_REGULAR);
201
202 return 1;
203}
204
205int trusts_loaddb(void) {
206 if(!trusts_connectdb())
207 return 0;
208
209 loaderror = 0;
210
211 trustsdb->loadtable(trustsdb, NULL, loadgroups_data, loadgroups_fini, NULL, "groups");
212 trustsdb->loadtable(trustsdb, NULL, loadhosts_data, loadhosts_fini, NULL, "hosts");
213
214 return 1;
215}
216
217void trusts_closedb(int closeconnection) {
218 if(!trustsdb)
219 return;
220
221 if(flushschedule) {
222 deleteschedule(flushschedule, flushdatabase, NULL);
223 flushschedule = NULL;
224
225 flushdatabase(NULL);
226 }
227
228 trusts_freeall();
229
230 trustsdbloaded = 0;
231 thmaxid = tgmaxid = 0;
232
233 if(closeconnection) {
234 trustsdb->close(trustsdb);
235 trustsdb = NULL;
236 }
237
238 triggerhook(HOOK_TRUSTS_DB_CLOSED, NULL);
239}
240
241static void th_dbupdatecounts(trusthost *th) {
242 trustsdb->squery(trustsdb, "UPDATE ? SET lastseen = ?, maxusage = ? WHERE id = ?", "Ttuu", "hosts", th->lastseen, th->maxusage, th->id);
243}
244
245static void tg_dbupdatecounts(trustgroup *tg) {
246 trustsdb->squery(trustsdb, "UPDATE ? SET lastseen = ?, maxusage = ? WHERE id = ?", "Ttuu", "groups", tg->lastseen, tg->maxusage, tg->id);
247}
248
249trusthost *th_copy(trusthost *ith) {
250 trusthost *th, *superset, *subset;
251
252 th = th_add(ith);
253 if(!th)
254 return NULL;
255
256 trustsdb_insertth("hosts", th, th->group->id);
257
258 th_getsuperandsubsets(ith->ip, ith->mask, &superset, &subset);
259 th_adjusthosts(th, subset, superset);
260
261 return th;
262}
263
264trusthost *th_new(trustgroup *tg, char *host) {
265 trusthost *th, nth;
266
267 if(!trusts_str2cidr(host, &nth.ip, &nth.mask))
268 return NULL;
269
270 nth.group = tg;
271 nth.id = thmaxid + 1;
272 nth.created = time(NULL);
273 nth.lastseen = 0;
274 nth.maxusage = 0;
275
276 th = th_copy(&nth);
277 if(!th)
278 return NULL;
279
280 thmaxid++;
281
282 return th;
283}
284
285trustgroup *tg_copy(trustgroup *itg) {
286 trustgroup *tg = tg_add(itg);
287 if(!tg)
288 return NULL;
289
290 trustsdb_inserttg("groups", tg);
291 return tg;
292}
293
294trustgroup *tg_new(trustgroup *itg) {
295 trustgroup *tg;
296
297 itg->id = tgmaxid + 1;
298 itg->maxusage = 0;
299 itg->lastseen = 0;
300 itg->lastmaxusereset = 0;
301
302 tg = tg_copy(itg);
303 if(!tg)
304 return NULL;
305
306 tgmaxid++;
307
308 return tg;
309}
310
311void trustsdb_insertth(char *table, trusthost *th, unsigned int groupid) {
312 trustsdb->squery(trustsdb,
313 "INSERT INTO ? (id, groupid, host, maxusage, created, lastseen) VALUES (?, ?, ?, ?, ?, ?)",
314 "Tuusuut", table, th->id, groupid, trusts_cidr2str(th->ip, th->mask), th->maxusage, th->created, th->lastseen
315 );
316}
317
318void trustsdb_inserttg(char *table, trustgroup *tg) {
319 trustsdb->squery(trustsdb,
320 "INSERT INTO ? (id, name, trustedfor, mode, maxperident, maxusage, expires, lastseen, lastmaxusereset, createdby, contact, comment) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
321 "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
322 );
323}
324
325void tg_update(trustgroup *tg) {
326 trustsdb->squery(trustsdb,
327 "UPDATE ? SET name = ?, trustedfor = ?, maxperident = ?, maxusage = ?, expires = ?, lastseen = ?, lastmaxusereset = ?, createdby = ?, contact = ?, comment = ? WHERE id = ?",
328 "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
329 );
330}
331
332void trustsdb_deletetg(char *table, trustgroup *tg) {
333 trustsdb->squery(trustsdb,
334 "DELETE FROM ? WHERE id = ?",
335 "Tu", "groups", tg->id);
336}
337
338void tg_delete(trustgroup *tg) {
339 trustgroup **pnext;
340
341 for(pnext=&tglist;*pnext;pnext=&((*pnext)->next)) {
342 if(*pnext == tg) {
343 *pnext = tg->next;
344 break;
345 }
346 }
347
348 trustsdb_deletetg("groups", tg);
349 tg_free(tg, 1);
350}
351
352void trustsdb_deleteth(char *table, trusthost *th) {
353 trustsdb->squery(trustsdb,
354 "DELETE FROM ? WHERE id = ?",
355 "Tu", "hosts", th->id);
356}
357
358void th_delete(trusthost *th) {
359 trusthost **pnext;
360 nick *np;
361
362 for(pnext=&(th->group->hosts);*pnext;pnext=&((*pnext)->next)) {
363 if(*pnext == th) {
364 *pnext = th->next;
365 break;
366 }
367 }
368
369 for(np=th->users;np;np=nextbytrust(np))
370 settrusthost(np, NULL);
371
372 th->group->count -= th->count;
373
374 trustsdb_deleteth("hosts", th);
375 th_free(th);
376}
377
378void trustlog(trustgroup *tg, const char *user, const char *format, ...) {
379 char buf[TRUSTLOGLEN+1];
380 va_list va;
381 unsigned int now;
382
383 va_start(va, format);
384 vsnprintf(buf, sizeof(buf), format, va);
385 va_end(va);
386
387 now = time(NULL);
388
389 trustsdb->squery(trustsdb,
390 "INSERT INTO ? (ts, groupid, groupname, username, message) VALUES (?, ?, ?, ?, ?)",
391 "Tuusss", "log", now, tg->id, tg->name->content, user, buf);
392}
393
394static void trustlogquery_callback(const struct DBAPIResult *result, void *arg) {
395 nick *np = (nick *)arg;
396 int rows = 0;
397
398 if(!result || !result->success) {
399 controlreply(np, "Error querying the log.");
400
401 if(result)
402 result->clear(result);
403
404 return;
405 }
406
407 while(result->next(result)) {
408 unsigned int ts, groupid;
409 char *groupname, *user, *message;
410
411 ts = strtoul(result->get(result, 0), NULL, 10);
412 groupid = strtoul(result->get(result, 1), NULL, 10);
413 groupname = result->get(result, 2);
414 user = result->get(result, 3);
415 message = result->get(result, 4);
416
417 controlreply(np, "[%s] #%d/%s (%s) %s", trusts_timetostr(ts), groupid, groupname, user, message);
418 rows++;
419 }
420
421 controlreply(np, "--- Done. Found %d entries.", rows);
422}
423
424void trustlogspewid(nick *np, unsigned int groupid, unsigned int limit) {
425 trustsdb->query(trustsdb, trustlogquery_callback, (void *)np,
426 "SELECT ts, groupid, groupname, username, message FROM ? WHERE groupid = ? ORDER BY ts DESC LIMIT ?",
427 "Tuu", "log", groupid, limit);
428}
429
430void trustlogspewname(nick *np, const char *groupname, unsigned int limit) {
431 trustsdb->query(trustsdb, trustlogquery_callback, (void *)np,
432 "SELECT ts, groupid, groupname, username, message FROM ? WHERE groupname = ? ORDER BY ts DESC LIMIT ?",
433 "Tsu", "log", groupname, limit);
434}
435
436void trustloggrep(nick *np, const char *pattern, unsigned int limit) {
437 char buf[512];
438 snprintf(buf, sizeof(buf), "%%%s%%", pattern);
439
440 trustsdb->query(trustsdb, trustlogquery_callback, (void *)np,
441 "SELECT ts, groupid, username, message FROM ? WHERE message LIKE ? ORDER BY ts DESC LIMIT ?",
442 "Tsu", "log", buf, limit);
443}
444
445void _init(void) {
446 trusts_connectdb();
447}
448
449void _fini(void) {
450 trusts_closedb(1);
451}