]> jfr.im git - irc/quakenet/newserv.git/blob - trusts/trusts_db.c
Implement pernodemax/nodebits for THs.
[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, 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
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 != 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(!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 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
129 static void loadhosts_fini(const DBAPIResult *result, void *tag) {
130 Error("trusts", ERR_INFO, "Finished loading hosts, maximum id: %d", thmaxid);
131 }
132
133 static 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
190 static void loadgroups_fini(const DBAPIResult *result, void *tag) {
191 Error("trusts", ERR_INFO, "Finished loading groups, maximum id: %d.", tgmaxid);
192 }
193
194 static 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
208 int 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
220 void 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
244 static 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
248 static 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
252 trusthost *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->mask, &superset, &subset);
262 th_adjusthosts(th, superset, subset);
263 th_linktree();
264
265 return th;
266 }
267
268 trusthost *th_new(trustgroup *tg, char *host) {
269 trusthost *th, nth;
270
271 if(!trusts_str2cidr(host, &nth.ip, &nth.mask))
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 th = th_copy(&nth);
281 if(!th)
282 return NULL;
283
284 thmaxid++;
285
286 return th;
287 }
288
289 trustgroup *tg_copy(trustgroup *itg) {
290 trustgroup *tg = tg_add(itg);
291 if(!tg)
292 return NULL;
293
294 trustsdb_inserttg("groups", tg);
295 return tg;
296 }
297
298 trustgroup *tg_new(trustgroup *itg) {
299 trustgroup *tg;
300
301 itg->id = tgmaxid + 1;
302 itg->maxusage = 0;
303 itg->lastseen = 0;
304 itg->lastmaxusereset = 0;
305
306 tg = tg_copy(itg);
307 if(!tg)
308 return NULL;
309
310 tgmaxid++;
311
312 return tg;
313 }
314
315 void trustsdb_insertth(char *table, trusthost *th, unsigned int groupid) {
316 trustsdb->squery(trustsdb,
317 "INSERT INTO ? (id, groupid, host, maxusage, created, lastseen, maxpernode, nodebits) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
318 "Tuusuutuu", table, th->id, groupid, trusts_cidr2str(th->ip, th->mask), th->maxusage, th->created, th->lastseen, th->maxpernode, th->nodebits
319 );
320 }
321
322 void trustsdb_inserttg(char *table, trustgroup *tg) {
323 trustsdb->squery(trustsdb,
324 "INSERT INTO ? (id, name, trustedfor, mode, maxperident, maxusage, expires, lastseen, lastmaxusereset, createdby, contact, comment) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
325 "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
326 );
327 }
328
329 void tg_update(trustgroup *tg) {
330 trustsdb->squery(trustsdb,
331 "UPDATE ? SET name = ?, trustedfor = ?, maxperident = ?, maxusage = ?, expires = ?, lastseen = ?, lastmaxusereset = ?, createdby = ?, contact = ?, comment = ? WHERE id = ?",
332 "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
333 );
334 }
335
336 void trustsdb_deletetg(char *table, trustgroup *tg) {
337 trustsdb->squery(trustsdb,
338 "DELETE FROM ? WHERE id = ?",
339 "Tu", "groups", tg->id);
340 }
341
342 void tg_delete(trustgroup *tg) {
343 trustgroup **pnext;
344
345 for(pnext=&tglist;*pnext;pnext=&((*pnext)->next)) {
346 if(*pnext == tg) {
347 *pnext = tg->next;
348 break;
349 }
350 }
351
352 trustsdb_deletetg("groups", tg);
353 tg_free(tg, 1);
354 }
355
356 void trustsdb_deleteth(char *table, trusthost *th) {
357 trustsdb->squery(trustsdb,
358 "DELETE FROM ? WHERE id = ?",
359 "Tu", "hosts", th->id);
360 }
361
362 void th_delete(trusthost *th) {
363 trusthost **pnext;
364 nick *np;
365
366 for(pnext=&(th->group->hosts);*pnext;pnext=&((*pnext)->next)) {
367 if(*pnext == th) {
368 *pnext = th->next;
369 break;
370 }
371 }
372
373 for(np=th->users;np;np=nextbytrust(np))
374 settrusthost(np, NULL);
375
376 th->group->count -= th->count;
377
378 trustsdb_deleteth("hosts", th);
379 th_free(th);
380
381 th_linktree();
382 }
383
384 void trustlog(trustgroup *tg, const char *user, const char *format, ...) {
385 char buf[TRUSTLOGLEN+1];
386 va_list va;
387 unsigned int now;
388
389 va_start(va, format);
390 vsnprintf(buf, sizeof(buf), format, va);
391 va_end(va);
392
393 now = time(NULL);
394
395 trustsdb->squery(trustsdb,
396 "INSERT INTO ? (ts, groupid, groupname, username, message) VALUES (?, ?, ?, ?, ?)",
397 "Tuusss", "log", now, tg->id, tg->name->content, user, buf);
398 }
399
400 static void trustlogquery_callback(const struct DBAPIResult *result, void *arg) {
401 nick *np = (nick *)arg;
402 int rows = 0;
403
404 if(!result || !result->success) {
405 controlreply(np, "Error querying the log.");
406
407 if(result)
408 result->clear(result);
409
410 return;
411 }
412
413 if(result->fields != 5) {
414 Error("trusts", ERR_ERROR, "Wrong number of fields in log table.");
415
416 result->clear(result);
417 return;
418 }
419
420 while(result->next(result)) {
421 unsigned int ts, groupid;
422 char *groupname, *user, *message;
423
424 ts = strtoul(result->get(result, 0), NULL, 10);
425 groupid = strtoul(result->get(result, 1), NULL, 10);
426 groupname = result->get(result, 2);
427 user = result->get(result, 3);
428 message = result->get(result, 4);
429
430 controlreply(np, "[%s] #%d/%s (%s) %s", trusts_timetostr(ts), groupid, groupname, user, message);
431 rows++;
432 }
433
434 result->clear(result);
435
436 controlreply(np, "--- Done. Found %d entries.", rows);
437 }
438
439 void trustlogspewid(nick *np, unsigned int groupid, unsigned int limit) {
440 trustsdb->query(trustsdb, trustlogquery_callback, (void *)np,
441 "SELECT ts, groupid, groupname, username, message FROM ? WHERE groupid = ? ORDER BY ts DESC LIMIT ?",
442 "Tuu", "log", groupid, limit);
443 }
444
445 void trustlogspewname(nick *np, const char *groupname, unsigned int limit) {
446 trustsdb->query(trustsdb, trustlogquery_callback, (void *)np,
447 "SELECT ts, groupid, groupname, username, message FROM ? WHERE groupname = ? ORDER BY ts DESC LIMIT ?",
448 "Tsu", "log", groupname, limit);
449 }
450
451 void trustloggrep(nick *np, const char *pattern, unsigned int limit) {
452 char buf[512];
453 snprintf(buf, sizeof(buf), "%%%s%%", pattern);
454
455 trustsdb->query(trustsdb, trustlogquery_callback, (void *)np,
456 "SELECT ts, groupid, groupname, username, message FROM ? WHERE message LIKE ? ORDER BY ts DESC LIMIT ?",
457 "Tsu", "log", buf, limit);
458 }
459
460 void _init(void) {
461 trusts_connectdb();
462 }
463
464 void _fini(void) {
465 trusts_closedb(1);
466 }