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