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