+#include <stdio.h>
+#include <stdarg.h>
+#include "../lib/version.h"
#include "../dbapi2/dbapi2.h"
#include "../core/error.h"
#include "../core/hooks.h"
#include "../core/schedule.h"
+#include "../control/control.h"
+#include "../irc/irc.h"
#include "trusts.h"
+MODULE_VERSION("");
+
DBAPIConn *trustsdb;
static int tgmaxid, thmaxid;
static int loaderror;
}
trustsdb->createtable(trustsdb, NULL, NULL,
- "CREATE TABLE ? (id INT PRIMARY KEY, name VARCHAR(?), trustedfor INT, mode INT, maxperident INT, maxusage INT, expires INT, lastseen INT, lastmaxuserreset INT, createdby VARCHAR(?), contact VARCHAR(?), comment VARCHAR(?))",
- "Tdddd", groups, TRUSTNAMELEN, NICKLEN, CONTACTLEN, COMMENTLEN
+ "CREATE TABLE ? (id INT PRIMARY KEY, name VARCHAR(?), trustedfor INT, flags INT, maxperident INT, maxusage INT, expires INT, lastseen INT, lastmaxusereset INT, createdby VARCHAR(?), contact VARCHAR(?), comment VARCHAR(?))",
+ "Tdddd", groups, TRUSTNAMELEN, CREATEDBYLEN, CONTACTLEN, COMMENTLEN
);
/* I'd like multiple keys here but that's not gonna happen on a cross-database platform :( */
- trustsdb->createtable(trustsdb, NULL, NULL, "CREATE TABLE ? (id INT PRIMARY KEY, groupid INT, host VARCHAR(?), maxusage INT, lastseen INT)", "Td", hosts, TRUSTHOSTLEN);
+ 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);
+
+ trustsdb->createtable(trustsdb, NULL, NULL,
+ "CREATE TABLE ? (groupid INT, groupname VARCHAR(?), ts INT, username VARCHAR(?), message VARCHAR(?))",
+ "Tddd", "log", TRUSTNAMELEN, CREATEDBYLEN, TRUSTLOGLEN
+ );
}
static void flushdatabase(void *arg) {
return;
}
- if(result->fields != 5) {
+ if(result->fields != 8) {
Error("trusts", ERR_ERROR, "Wrong number of fields in hosts table.");
loaderror = 1;
}
while(result->next(result)) {
- unsigned int groupid, id;
+ unsigned int groupid;
+ trusthost th;
char *host;
- unsigned int maxusage, lastseen;
- trustgroup *tg;
- id = strtoul(result->get(result, 0), NULL, 10);
- if(id > thmaxid)
- thmaxid = id;
+ th.id = strtoul(result->get(result, 0), NULL, 10);
+ if(th.id > thmaxid)
+ thmaxid = th.id;
groupid = strtoul(result->get(result, 1), NULL, 10);
- tg = tg_getbyid(groupid);
- if(!tg) {
+ th.group = tg_getbyid(groupid);
+ if(!th.group) {
Error("trusts", ERR_WARNING, "Orphaned trust group host: %d", groupid);
continue;
}
- /* NOTE: 2 is at the bottom */
- maxusage = strtoul(result->get(result, 3), NULL, 10);
- lastseen = (time_t)strtoul(result->get(result, 4), NULL, 10);
host = result->get(result, 2);
+ if(!ipmask_parse(host, &th.ip, &th.bits)) {
+ Error("trusts", ERR_WARNING, "Error parsing cidr for host: %s", host);
+ continue;
+ }
+
+ th.maxusage = strtoul(result->get(result, 3), NULL, 10);
+ th.created = (time_t)strtoul(result->get(result, 4), NULL, 10);
+ th.lastseen = (time_t)strtoul(result->get(result, 5), NULL, 10);
+ th.maxpernode = strtol(result->get(result, 6), NULL, 10);
+ th.nodebits = strtol(result->get(result, 7), NULL, 10);
- if(!th_add(tg, id, host, maxusage, lastseen))
+ if(!th_add(&th))
Error("trusts", ERR_WARNING, "Error adding host to trust %d: %s", groupid, host);
}
}
while(result->next(result)) {
- unsigned int id;
- sstring *name, *createdby, *contact, *comment;
- unsigned int trustedfor, mode, maxperident, maxusage;
- time_t expires, lastseen, lastmaxuserreset;
-
- id = strtoul(result->get(result, 0), NULL, 10);
- if(id > tgmaxid)
- tgmaxid = id;
-
- name = getsstring(result->get(result, 1), TRUSTNAMELEN);
- trustedfor = strtoul(result->get(result, 2), NULL, 10);
- mode = atoi(result->get(result, 3));
- maxperident = strtoul(result->get(result, 4), NULL, 10);
- maxusage = strtoul(result->get(result, 5), NULL, 10);
- expires = (time_t)strtoul(result->get(result, 6), NULL, 10);
- lastseen = (time_t)strtoul(result->get(result, 7), NULL, 10);
- lastmaxuserreset = (time_t)strtoul(result->get(result, 8), NULL, 10);
- createdby = getsstring(result->get(result, 9), NICKLEN);
- contact = getsstring(result->get(result, 10), CONTACTLEN);
- comment = getsstring(result->get(result, 11), COMMENTLEN);
-
- if(name && createdby && contact && comment) {
- if(!tg_add(id, name->content, trustedfor, mode, maxperident, maxusage, expires, lastseen, lastmaxuserreset, createdby->content, contact->content, comment->content))
- Error("trusts", ERR_WARNING, "Error adding trustgroup %d: %s", id, name->content);
+ trustgroup tg;
+
+ tg.id = strtoul(result->get(result, 0), NULL, 10);
+ if(tg.id > tgmaxid)
+ tgmaxid = tg.id;
+
+ tg.name = getsstring(rtrim(result->get(result, 1)), TRUSTNAMELEN);
+ tg.trustedfor = strtoul(result->get(result, 2), NULL, 10);
+ tg.flags = atoi(result->get(result, 3));
+ tg.maxperident = strtoul(result->get(result, 4), NULL, 10);
+ tg.maxusage = strtoul(result->get(result, 5), NULL, 10);
+ tg.expires = (time_t)strtoul(result->get(result, 6), NULL, 10);
+ tg.lastseen = (time_t)strtoul(result->get(result, 7), NULL, 10);
+ tg.lastmaxusereset = (time_t)strtoul(result->get(result, 8), NULL, 10);
+ tg.createdby = getsstring(rtrim(result->get(result, 9)), CREATEDBYLEN);
+ tg.contact = getsstring(rtrim(result->get(result, 10)), CONTACTLEN);
+ tg.comment = getsstring(rtrim(result->get(result, 11)), COMMENTLEN);
+
+ if(tg.name && tg.createdby && tg.contact && tg.comment) {
+ if(!tg_add(&tg))
+ Error("trusts", ERR_WARNING, "Error adding trustgroup %d: %s", tg.id, tg.name->content);
} else {
- Error("trusts", ERR_ERROR, "Error allocating sstring in group loader, id: %d", id);
+ Error("trusts", ERR_ERROR, "Error allocating sstring in group loader, id: %d", tg.id);
}
- freesstring(name);
- freesstring(createdby);
- freesstring(contact);
- freesstring(comment);
+ freesstring(tg.name);
+ freesstring(tg.createdby);
+ freesstring(tg.contact);
+ freesstring(tg.comment);
}
result->clear(result);
Error("trusts", ERR_INFO, "Finished loading groups, maximum id: %d.", tgmaxid);
}
-int trusts_loaddb(void) {
+static int trusts_connectdb(void) {
if(!trustsdb) {
- trustsdb = dbapi2open(NULL, "trusts");
+ trustsdb = dbapi2open("sqlite", "trusts");
if(!trustsdb) {
Error("trusts", ERR_WARNING, "Unable to connect to db -- not loaded.");
return 0;
createtrusttables(TABLES_REGULAR);
+ return 1;
+}
+
+int trusts_loaddb(void) {
+ if(!trusts_connectdb())
+ return 0;
+
loaderror = 0;
trustsdb->loadtable(trustsdb, NULL, loadgroups_data, loadgroups_fini, NULL, "groups");
trustsdb->squery(trustsdb, "UPDATE ? SET lastseen = ?, maxusage = ? WHERE id = ?", "Ttuu", "groups", tg->lastseen, tg->maxusage, tg->id);
}
-trusthost *th_new(trustgroup *tg, char *host) {
+trusthost *th_copy(trusthost *ith) {
trusthost *th, *superset, *subset;
- u_int32_t ip, mask;
- /* ugh */
- if(!trusts_str2cidr(host, &ip, &mask))
+ th = th_add(ith);
+ if(!th)
return NULL;
- th_getsuperandsubsets(ip, mask, &superset, &subset);
+ trustsdb_insertth("hosts", th, th->group->id);
+
+ th_getsuperandsubsets(&ith->ip, ith->bits, &superset, &subset);
+ th_adjusthosts(th, superset, subset);
+ th_linktree();
+
+ return th;
+}
+
+trusthost *th_new(trustgroup *tg, char *host) {
+ trusthost *th, nth;
- th = th_add(tg, thmaxid + 1, host, 0, 0);
+ if(!ipmask_parse(host, &nth.ip, &nth.bits))
+ return NULL;
+
+ nth.group = tg;
+ nth.id = thmaxid + 1;
+ nth.created = getnettime();
+ nth.lastseen = 0;
+ nth.maxusage = 0;
+
+ nth.maxpernode = 0;
+ nth.nodebits = (irc_in_addr_is_ipv4(&nth.ip))?128:64;
+
+ if (nth.bits < nth.nodebits)
+ nth.nodebits = nth.bits;
+
+ th = th_copy(&nth);
if(!th)
return NULL;
thmaxid++;
- trustsdb->squery(trustsdb,
- "INSERT INTO ? (id, groupid, host, maxusage, lastseen) VALUES (?, ?, ?, ?, ?)",
- "Tuusut", "hosts", th->id, tg->id, trusts_cidr2str(th->ip, th->mask), th->maxusage, th->lastseen
- );
+ return th;
+}
- th_adjusthosts(th, subset, superset);
+trustgroup *tg_copy(trustgroup *itg) {
+ trustgroup *tg = tg_add(itg);
+ if(!tg)
+ return NULL;
- th_linktree();
- return th;
+ trustsdb_inserttg("groups", tg);
+ return tg;
}
-trustgroup *tg_new(char *name, unsigned int trustedfor, int mode, unsigned int maxperident, time_t expires, char *createdby, char *contact, char *comment) {
- trustgroup *tg = tg_add(tgmaxid + 1, name, trustedfor, mode, maxperident, 0, expires, 0, 0, createdby, contact, comment);
+trustgroup *tg_new(trustgroup *itg) {
+ trustgroup *tg;
+
+ itg->id = tgmaxid + 1;
+ itg->maxusage = 0;
+ itg->lastseen = 0;
+ itg->lastmaxusereset = 0;
+
+ tg = tg_copy(itg);
if(!tg)
return NULL;
tgmaxid++;
+ return tg;
+}
+
+void trustsdb_insertth(char *table, trusthost *th, unsigned int groupid) {
trustsdb->squery(trustsdb,
- "INSERT INTO ? (id, name, trustedfor, mode, maxperident, maxusage, expires, lastseen, lastmaxuserreset, createdby, contact, comment) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
- "Tusuuuutttsss", "groups", tg->id, tg->name->content, tg->trustedfor, tg->mode, tg->maxperident, tg->maxusage, tg->expires, tg->lastseen, tg->lastmaxuserreset, tg->createdby->content, tg->contact->content, tg->comment->content
+ "INSERT INTO ? (id, groupid, host, maxusage, created, lastseen, maxpernode, nodebits) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
+ "Tuusuutuu", table, th->id, groupid, CIDRtostr(th->ip, th->bits), th->maxusage, th->created, th->lastseen, th->maxpernode, th->nodebits
);
+}
- return tg;
+void trustsdb_inserttg(char *table, trustgroup *tg) {
+ trustsdb->squery(trustsdb,
+ "INSERT INTO ? (id, name, trustedfor, flags, maxperident, maxusage, expires, lastseen, lastmaxusereset, createdby, contact, comment) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
+ "Tusuuuutttsss", table, tg->id, tg->name->content, tg->trustedfor, tg->flags, tg->maxperident, tg->maxusage, tg->expires, tg->lastseen, tg->lastmaxusereset, tg->createdby->content, tg->contact->content, tg->comment->content
+ );
+}
+
+void tg_update(trustgroup *tg) {
+ trustsdb->squery(trustsdb,
+ "UPDATE ? SET name = ?, trustedfor = ?, flags = ?, maxperident = ?, maxusage = ?, expires = ?, lastseen = ?, lastmaxusereset = ?, createdby = ?, contact = ?, comment = ? WHERE id = ?",
+ "Tsuuuutttsssu", "groups", tg->name->content, tg->trustedfor, tg->flags, tg->maxperident, tg->maxusage, tg->expires, tg->lastseen, tg->lastmaxusereset, tg->createdby->content, tg->contact->content, tg->comment->content, tg->id
+ );
+}
+
+void trustsdb_deletetg(char *table, trustgroup *tg) {
+ trustsdb->squery(trustsdb,
+ "DELETE FROM ? WHERE id = ?",
+ "Tu", "groups", tg->id);
+}
+
+void tg_delete(trustgroup *tg) {
+ trustgroup **pnext;
+
+ for(pnext=&tglist;*pnext;pnext=&((*pnext)->next)) {
+ if(*pnext == tg) {
+ *pnext = tg->next;
+ break;
+ }
+ }
+
+ trustsdb_deletetg("groups", tg);
+ tg_free(tg, 1);
+}
+
+void th_update(trusthost *th) {
+ trustsdb->squery(trustsdb,
+ "UPDATE ? SET maxpernode = ?, nodebits = ? WHERE id = ?",
+ "Tuuu", "hosts", th->maxpernode, th->nodebits, th->id
+ );
+}
+
+void trustsdb_deleteth(char *table, trusthost *th) {
+ trustsdb->squery(trustsdb,
+ "DELETE FROM ? WHERE id = ?",
+ "Tu", "hosts", th->id);
+}
+
+void th_delete(trusthost *th) {
+ trusthost **pnext;
+ nick *np;
+
+ for(pnext=&(th->group->hosts);*pnext;pnext=&((*pnext)->next)) {
+ if(*pnext == th) {
+ *pnext = th->next;
+ break;
+ }
+ }
+
+ if(th->parent) {
+ for(pnext=&(th->parent->children);*pnext;pnext=&((*pnext)->nextbychild)) {
+ if(*pnext == th) {
+ *pnext = th->nextbychild;
+ break;
+ }
+ }
+ }
+
+ for(np=th->users;np;np=nextbytrust(np))
+ settrusthost(np, NULL);
+
+ th->group->count -= th->count;
+
+ if(th->parent) {
+ th->parent->count += th->count;
+
+ if(th->lastseen > th->parent->lastseen)
+ th->parent->lastseen = th->lastseen;
+ }
+
+ trustsdb_deleteth("hosts", th);
+ th_free(th);
+
+ th_linktree();
+}
+
+void trustlog(trustgroup *tg, const char *user, const char *format, ...) {
+ char buf[TRUSTLOGLEN+1];
+ va_list va;
+ unsigned int now;
+
+ va_start(va, format);
+ vsnprintf(buf, sizeof(buf), format, va);
+ va_end(va);
+
+ now = time(NULL);
+
+ trustsdb->squery(trustsdb,
+ "INSERT INTO ? (ts, groupid, groupname, username, message) VALUES (?, ?, ?, ?, ?)",
+ "Tuusss", "log", now, tg->id, tg->name->content, user, buf);
+}
+
+static void trustlogquery_callback(const struct DBAPIResult *result, void *arg) {
+ nick *np = (nick *)arg;
+ int rows = 0;
+
+ if(!result || !result->success) {
+ controlreply(np, "Error querying the log.");
+
+ if(result)
+ result->clear(result);
+
+ return;
+ }
+
+ if(result->fields != 5) {
+ Error("trusts", ERR_ERROR, "Wrong number of fields in log table.");
+
+ result->clear(result);
+ return;
+ }
+
+ while(result->next(result)) {
+ unsigned int ts, groupid;
+ char *groupname, *user, *message;
+
+ ts = strtoul(result->get(result, 0), NULL, 10);
+ groupid = strtoul(result->get(result, 1), NULL, 10);
+ groupname = result->get(result, 2);
+ user = result->get(result, 3);
+ message = result->get(result, 4);
+
+ controlreply(np, "[%s] #%d/%s (%s) %s", trusts_timetostr(ts), groupid, groupname, user, message);
+ rows++;
+ }
+
+ result->clear(result);
+
+ controlreply(np, "--- Done. Found %d entries.", rows);
+}
+
+void trustlogspewid(nick *np, unsigned int groupid, unsigned int limit) {
+ trustsdb->query(trustsdb, trustlogquery_callback, (void *)np,
+ "SELECT ts, groupid, groupname, username, message FROM ? WHERE groupid = ? ORDER BY ts DESC LIMIT ?",
+ "Tuu", "log", groupid, limit);
+}
+
+void trustlogspewname(nick *np, const char *groupname, unsigned int limit) {
+ trustsdb->query(trustsdb, trustlogquery_callback, (void *)np,
+ "SELECT ts, groupid, groupname, username, message FROM ? WHERE groupname = ? ORDER BY ts DESC LIMIT ?",
+ "Tsu", "log", groupname, limit);
+}
+
+void trustloggrep(nick *np, const char *pattern, unsigned int limit) {
+ char buf[512];
+ snprintf(buf, sizeof(buf), "%%%s%%", pattern);
+
+ trustsdb->query(trustsdb, trustlogquery_callback, (void *)np,
+ "SELECT ts, groupid, groupname, username, message FROM ? WHERE message LIKE ? ORDER BY ts DESC LIMIT ?",
+ "Tsu", "log", buf, limit);
}
void _init(void) {
- trusts_loaddb();
+ trusts_connectdb();
}
void _fini(void) {