Add replication functionality via a master/slave protocol.
Refactor all database inserting, and all paramters for t{g,h}_{copy,new,add}.
Refactor all parsers and add trustdump.
Add trustforceresync and trustsync.
#define HOOK_TRUSTS_LOSTNICK 903 /* Argument is void*[2] (nick*, long) */
#define HOOK_TRUSTS_NEWGROUP 904 /* Argument is trustgroup* */
#define HOOK_TRUSTS_LOSTGROUP 905 /* Argument is trustgroup* */
+#define HOOK_TRUSTS_ADDGROUP 906 /* Argument is trustgroup* */
+#define HOOK_TRUSTS_DELGROUP 907 /* Argument is trustgroup* */
+#define HOOK_TRUSTS_ADDHOST 908 /* Argument is trusthost* */
+#define HOOK_TRUSTS_DELHOST 909 /* Argument is trusthost* */
#define PRIORITY_DEFAULT 0
trusts_master.so: trusts_master.o
-trusts_slave.so: trusts_slave.o
+trusts_slave.so: trusts_slave.o db-slave.o
dirs: $(TRUSTSDIRS)
ln -sf */*.so .
th_updatechildren(th->parent);
}
-trusthost *th_add(trustgroup *tg, unsigned int id, char *host, unsigned int maxusage, time_t lastseen) {
- uint32_t ip, mask;
+trusthost *th_add(trusthost *ith) {
trusthost *th;
- if(!trusts_str2cidr(host, &ip, &mask))
- return NULL;
-
th = nsmalloc(POOL_TRUSTS, sizeof(trusthost));
if(!th)
return NULL;
- th->id = id;
- th->maxusage = maxusage;
- th->lastseen = lastseen;
- th->ip = ip;
- th->mask = mask;
+ memcpy(th, ith, sizeof(trusthost));
th->users = NULL;
- th->group = tg;
th->count = 0;
th->parent = NULL;
th->marker = 0;
- th->next = tg->hosts;
- tg->hosts = th;
+ th->next = th->group->hosts;
+ th->group->hosts = th;
return th;
}
nsfree(POOL_TRUSTS, tg);
}
-trustgroup *tg_add(unsigned int id, char *name, unsigned int trustedfor, int mode, unsigned int maxperident, unsigned int maxusage, time_t expires, time_t lastseen, time_t lastmaxuserreset, char *createdby, char *contact, char *comment) {
+trustgroup *tg_add(trustgroup *itg) {
trustgroup *tg = nsmalloc(POOL_TRUSTS, sizeof(trustgroup));
if(!tg)
return NULL;
- tg->name = getsstring(name, TRUSTNAMELEN);
- tg->createdby = getsstring(createdby, NICKLEN);
- tg->contact = getsstring(contact, CONTACTLEN);
- tg->comment = getsstring(comment, COMMENTLEN);
+ memcpy(tg, itg, sizeof(trustgroup));
+
+ tg->name = getsstring(tg->name->content, TRUSTNAMELEN);
+ tg->createdby = getsstring(tg->createdby->content, NICKLEN);
+ tg->contact = getsstring(tg->contact->content, CONTACTLEN);
+ tg->comment = getsstring(tg->comment->content, COMMENTLEN);
if(!tg->name || !tg->createdby || !tg->contact || !tg->comment) {
tg_free(tg);
return NULL;
}
- tg->id = id;
- tg->trustedfor = trustedfor;
- tg->mode = mode;
- tg->maxperident = maxperident;
- tg->maxusage = maxusage;
- tg->expires = expires;
- tg->lastseen = lastseen;
- tg->lastmaxuserreset = lastmaxuserreset;
tg->hosts = NULL;
-
tg->marker = 0;
-
tg->count = 0;
memset(tg->exts, 0, sizeof(tg->exts));
return thmarker;
}
+
+trustgroup *tg_inttotg(unsigned int id) {
+ trustgroup *tg;
+
+ for(tg=tglist;tg;tg=tg->next)
+ if(tg->id == id)
+ return tg;
+
+ return NULL;
+}
+
extern DBAPIConn *trustsdb;
static trustmigration *migration;
-static void tm_group(void *, unsigned int, char *, unsigned int, unsigned int, unsigned int, unsigned int, time_t, time_t, time_t, char *, char *, char *);
-static void tm_host(void *, unsigned int, char *, unsigned int, time_t);
+static void tm_group(void *, trustgroup *);
+static void tm_host(void *, trusthost *, unsigned int);
static void tm_final(void *, int);
trustmigration *migration_start(TrustMigrationGroup, TrustMigrationHost, TrustMigrationFini, void *);
void migration_stop(trustmigration *);
-void createtrusttables(int migration);
+void createtrusttables(int);
struct callbackdata {
void *tag;
migration_stop(migration);
}
-static void tm_group(void *tag, unsigned int id, char *name, unsigned int trustedfor, unsigned int mode, unsigned int maxperident, unsigned int maxusage, time_t expires, time_t lastseen, time_t lastmaxuserreset, char *createdby, char *contact, char *comment) {
- if(id % 25 == 0)
- Error("trusts", ERR_INFO, "Migration currently at id: %d", id);
+static void tm_group(void *tag, trustgroup *tg) {
+ if(tg->id % 25 == 0)
+ Error("trusts_migration", ERR_INFO, "Migration currently at id: %d", tg->id);
- trustsdb->squery(trustsdb,
- "INSERT INTO ? (id, name, trustedfor, mode, maxperident, maxusage, expires, lastseen, lastmaxuserreset, createdby, contact, comment) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
- "Tusuuuutttsss", "migration_groups", id, name, trustedfor, mode, maxperident, maxusage, expires, lastseen, lastmaxuserreset, createdby, contact, comment
- );
+ trustsdb_inserttg("migration_groups", tg);
}
-static void tm_host(void *tag, unsigned int id, char *host, unsigned int maxusage, time_t lastseen) {
+static void tm_host(void *tag, trusthost *th, unsigned int groupid) {
struct callbackdata *cbd = tag;
- trustsdb->squery(trustsdb,
- "INSERT INTO ? (id, groupid, host, maxusage, lastseen) VALUES (?, ?, ?, ?, ?)",
- "Tuusut", "migration_hosts", cbd->hostid++, id, host, maxusage, lastseen
- );
+ th->id = cbd->hostid++;
+ trustsdb_insertth("migration_hosts", th, groupid);
}
static void tm_complete(const DBAPIResult *r, void *tag) {
errcode = MIGRATION_STOPPED;
} else {
if(!r->success) {
- Error("trusts", ERR_ERROR, "A error occured executing the rename table query.");
+ Error("trusts_migration", ERR_ERROR, "A error occured executing the rename table query.");
errcode = MIGRATION_LASTERROR;
} else {
- Error("trusts", ERR_INFO, "Migration table copying complete.");
+ Error("trusts_migration", ERR_INFO, "Migration table copying complete.");
}
r->clear(r);
}
migration = NULL;
if(errcode) {
- Error("trusts", ERR_ERROR, "Migration error: %d", errcode);
+ Error("trusts_migration", ERR_ERROR, "Migration error: %d", errcode);
if(cbd) {
cbd->callback(errcode, cbd->tag);
nsfree(POOL_TRUSTS, cbd);
} else {
trusts_closedb(0);
- Error("trusts", ERR_INFO, "Migration completed, copying tables...");
+ Error("trusts_migration", ERR_INFO, "Migration completed, copying tables...");
trustsdb->squery(trustsdb, "BEGIN TRANSACTION", "");
trustsdb->squery(trustsdb, "DROP TABLE ?", "T", "groups");
--- /dev/null
+#include "../dbapi2/dbapi2.h"
+#include "../core/error.h"
+#include "trusts.h"
+
+extern DBAPIConn *trustsdb;
+
+void createtrusttables(int);
+void trusts_replication_complete(int);
+
+void trusts_replication_createtables(void) {
+ createtrusttables(TABLES_REPLICATION);
+ trustsdb->squery(trustsdb, "DELETE FROM ?", "T", "replication_groups");
+ trustsdb->squery(trustsdb, "DELETE FROM ?", "T", "replication_hosts");
+}
+
+static void tr_complete(const DBAPIResult *r, void *tag) {
+ if(!r) {
+ trusts_replication_complete(1);
+ } else {
+ if(!r->success) {
+ Error("trusts_slave", ERR_ERROR, "A error occured executing the rename table query.");
+ trusts_replication_complete(2);
+ } else {
+ Error("trusts_slave", ERR_INFO, "Migration table copying complete.");
+ trusts_replication_complete(0);
+ }
+ r->clear(r);
+ }
+}
+
+void trusts_replication_swap(void) {
+ trusts_closedb(0);
+
+ Error("trusts_slave", ERR_INFO, "Copying tables...");
+
+ trustsdb->squery(trustsdb, "BEGIN TRANSACTION", "");
+ trustsdb->squery(trustsdb, "DROP TABLE ?", "T", "groups");
+ trustsdb->squery(trustsdb, "ALTER TABLE ? RENAME TO ?", "Ts", "replication_groups", "groups");
+ trustsdb->squery(trustsdb, "DROP TABLE ?", "T", "hosts");
+ trustsdb->squery(trustsdb, "ALTER TABLE ? RENAME TO ?", "Ts", "replication_hosts", "hosts");
+ trustsdb->query(trustsdb, tr_complete, NULL, "COMMIT", "");
+}
#include <stdio.h>
#include <stdint.h>
#include <time.h>
+#include <string.h>
+#include <stdlib.h>
+#include "../lib/strlfunc.h"
+#include "trusts.h"
int trusts_parsecidr(const char *host, uint32_t *ip, short *mask) {
unsigned int octet1 = 0, octet2 = 0, octet3 = 0, octet4 = 0, umask = 32;
return buf;
}
+char *dumpth(trusthost *th, int oformat) {
+ static char buf[512];
+
+ if(oformat) {
+ snprintf(buf, sizeof(buf), "#%u,%s,%u,%u,%jd", th->group->id, trusts_cidr2str(th->ip, th->mask), th->count, th->maxusage, (intmax_t)th->lastseen);
+ } else {
+ snprintf(buf, sizeof(buf), "%u,%s,%u,%u,%jd", th->group->id, trusts_cidr2str(th->ip, th->mask), th->id, th->maxusage, (intmax_t)th->lastseen);
+ }
+
+ return buf;
+}
+
+char *dumptg(trustgroup *tg, int oformat) {
+ static char buf[512];
+
+ if(oformat) {
+ snprintf(buf, sizeof(buf), "#%u,%s,%u,%u,%d,%u,%u,%jd,%jd,%jd,%s,%s,%s", tg->id, tg->name->content, tg->count, tg->trustedfor, tg->mode, tg->maxperident, tg->maxusage, (intmax_t)tg->expires, (intmax_t)tg->lastseen, (intmax_t)tg->lastmaxuserreset, tg->createdby->content, tg->contact->content, tg->comment->content);
+ } else {
+ snprintf(buf, sizeof(buf), "%u,%s,%u,%d,%u,%u,%jd,%jd,%jd,%s,%s,%s", tg->id, tg->name->content, tg->trustedfor, tg->mode, tg->maxperident, tg->maxusage, (intmax_t)tg->expires, (intmax_t)tg->lastseen, (intmax_t)tg->lastmaxuserreset, tg->createdby->content, tg->contact->content, tg->comment->content);
+ }
+
+ return buf;
+}
+
+int parsetg(char *buf, trustgroup *tg, int oformat) {
+ char *line, *createdby, *contact, *comment, *name, *id;
+ unsigned long expires, lastseen, lastmaxusereset;
+ char xbuf[1024];
+ int pos;
+
+/* #id,ticket35153,14,20,1,1,17,1879854575,1222639249,0,nterfacer,Qwhois&2120764,Non-Commercial Bouncer (Created by: doomie)
+ ,name ,current
+ ,trustedfor
+ ,mode
+ ,maxperident
+ ,maxusage
+ ,expires ,lastseen ,lastmaxusereset
+ ,createdby,contact ,comment
+*/
+ int r;
+
+ strlcpy(xbuf, buf, sizeof(xbuf));
+ line = xbuf;
+
+ if(!*line)
+ return 0;
+
+ if(oformat) {
+ if(line[0] != '#')
+ return 0;
+ line++;
+ }
+
+ id = line;
+ line = strchr(xbuf, ',');
+ if(!line)
+ return 0;
+ *line++ = '\0';
+
+ tg->id = strtoul(id, NULL, 10);
+ if(!tg->id)
+ return 0;
+
+ name = line;
+ line = strchr(line, ',');
+ if(!line)
+ return 0;
+ *line++ = '\0';
+
+ if(oformat) {
+ r = sscanf(line, "%*u,%u,%u,%u,%u,%lu,%lu,%lu,%n",
+ /*current, */ &tg->trustedfor, &tg->mode, &tg->maxperident,
+ &tg->maxusage, &expires, &lastseen, &lastmaxusereset, &pos);
+ } else {
+ r = sscanf(line, "%u,%u,%u,%u,%lu,%lu,%lu,%n",
+ &tg->trustedfor, &tg->mode, &tg->maxperident,
+ &tg->maxusage, &expires, &lastseen, &lastmaxusereset, &pos);
+ }
+ if(r != 7)
+ return 0;
+
+ tg->expires = (time_t)expires;
+ tg->lastseen = (time_t)lastseen;
+ tg->lastmaxuserreset = (time_t)lastmaxusereset;
+
+ createdby = &line[pos];
+ contact = strchr(createdby, ',');
+ if(!contact)
+ return 0;
+ *contact++ = '\0';
+
+ comment = strchr(contact, ',');
+ if(!comment)
+ return 0;
+ *comment++ = '\0';
+
+ tg->name = getsstring(name, TRUSTNAMELEN);
+ tg->createdby = getsstring(createdby, NICKLEN);
+ tg->comment = getsstring(comment, COMMENTLEN);
+ tg->contact = getsstring(contact, CONTACTLEN);
+ if(!tg->name || !tg->createdby || !tg->comment || !tg->contact) {
+ freesstring(tg->name);
+ freesstring(tg->createdby);
+ freesstring(tg->comment);
+ freesstring(tg->contact);
+ return 0;
+ }
+
+ return 1;
+}
+
+int parseth(char *line, trusthost *th, unsigned int *tgid, int oformat) {
+ unsigned long lastseen;
+ char *ip, xbuf[1024], *id;
+
+/* #id,213.230.192.128/26,20,23,1222732944
+ ip ,cur,max,lastseen */
+
+ strlcpy(xbuf, line, sizeof(xbuf));
+ id = line = xbuf;
+
+ line = strchr(line, ',');
+ if(!line)
+ return 0;
+ *line++ = '\0';
+
+ *tgid = strtoul(id, NULL, 10);
+ if(!*tgid)
+ return 0;
+
+ ip = line;
+ line = strchr(line, ',');
+ if(!line)
+ return 0;
+ *line++ = '\0';
+
+ if(!trusts_str2cidr(ip, &th->ip, &th->mask))
+ return 0;
+
+ if(oformat) {
+ if(sscanf(line, "%*u,%u,%lu", /*current, */&th->maxusage, &lastseen) != 2)
+ return 0;
+ } else {
+ if(sscanf(line, "%u,%u,%lu", &th->id, &th->maxusage, &lastseen) != 3)
+ return 0;
+ }
+
+ th->lastseen = (time_t)lastseen;
+
+ return 1;
+}
+
+char *rtrim(char *buf) {
+ static char obuf[1024];
+ size_t len = strlcpy(obuf, buf, sizeof(obuf));
+
+ if((len < sizeof(obuf)) && (len > 0)) {
+ size_t i;
+ for(i=len-1;i>=0;i--) {
+ if(obuf[i] != ' ')
+ break;
+
+ obuf[i] = '\0';
+ }
+ }
+
+ return obuf;
+}
tm_fini(tm, MIGRATION_STOPPED);
}
-static int tm_parsegroup(trustmigration *tm, unsigned int id, const char *oline) {
- char *line, *createdby, *contact, *comment, *name;
- unsigned int trustedfor, maxperident, mode, maxusage;
- unsigned long expires, lastseen, lastmaxusereset;
- char xbuf[1024];
- int pos;
-
-/* ticket35153,14,20,1,1,17,1879854575,1222639249,0,nterfacer,Qwhois&2120764,Non-Commercial Bouncer (Created by: doomie)
- name ,current
- ,trustedfor
- ,mode
- ,maxperident
- ,maxusage
- ,expires ,lastseen ,lastmaxusereset
- ,createdby,contact ,comment
-*/
- int r;
-
- strlcpy(xbuf, oline, sizeof(xbuf));
- name = xbuf;
-
- line = strchr(name, ',');
- if(!line)
- return 1;
- *line++ = '\0';
-
- r = sscanf(line, "%*u,%u,%u,%u,%u,%lu,%lu,%lu,%n",
- /*current, */ &trustedfor, &mode, &maxperident,
- &maxusage, &expires, &lastseen, &lastmaxusereset, &pos);
- if(r != 7)
- return 2;
-
- createdby = &line[pos];
- contact = strchr(createdby, ',');
- if(!contact)
- return 3;
- *contact++ = '\0';
-
- comment = strchr(contact, ',');
- if(!comment)
- return 4;
- *comment++ = '\0';
-
- tm->group(tm->tag, id, name, trustedfor, mode, maxperident, maxusage, (time_t)expires, (time_t)lastseen, (time_t)lastmaxusereset, createdby, contact, comment);
- return 0;
-}
-
-static int tm_parsehost(trustmigration *tm, unsigned int id, char *line) {
- unsigned int max;
- unsigned long lastseen;
- char *ip, xbuf[1024];
-
-/* 213.230.192.128/26,20,23,1222732944
- ip ,cur,max,lastseen */
-
- strlcpy(xbuf, line, sizeof(xbuf));
- ip = line = xbuf;
-
- line = strchr(line, ',');
- if(!line)
- return 5;
- *line++ = '\0';
-
- if(sscanf(line, "%*u,%u,%lu", /*current, */&max, &lastseen) != 2)
- return 6;
-
- tm->host(tm->tag, id, ip, max, lastseen);
- return 0;
-}
-
static void tm_stage2(int failure, int linec, char **linev, void *tag) {
trustmigration *tm = tag;
char *finishline;
for(i=0;i<linec-1;i++) {
char *linestart = &linev[i][2], type = linev[i][0];
- if(type == 'G' || type == 'H') {
- char *realline;
- unsigned int id;
- int pos, ret;
+ if(type == 'G') {
+ trustgroup tg;
- if(sscanf(linestart, "#%u,%n", &id, &pos) != 1) {
- tm_fini(tm, 10);
+ if(!parsetg(linestart, &tg, 1)) {
+ tm_fini(tm, 150);
return;
}
- if(id > tm->cur) {
- /* this one is missing and we've received a later one instead, update tm->cur to point to this one */
- tm->cur = id;
- } else if(id < tm->cur) {
+ if(tg.id >= tm->cur)
+ tm->group(tm->tag, &tg);
+
+ freesstring(tg.name);
+ freesstring(tg.createdby);
+ freesstring(tg.contact);
+ freesstring(tg.comment);
+
+ if(tg.id < tm->cur) {
tm_fini(tm, 11);
return;
}
- realline = &linestart[pos];
- if(type == 'G') {
- ret = tm_parsegroup(tm, id, realline);
- } else {
- ret = tm_parsehost(tm, id, realline);
+ if(tg.id > tm->cur)
+ tm->cur = tg.id;
+ } else if (type == 'H') {
+ trusthost th;
+ unsigned int groupid;
+
+ if(!parseth(linestart, &th, &groupid, 1)) {
+ tm_fini(tm, 151);
+ return;
}
- if(ret) {
- tm_fini(tm, ret);
+
+ if(groupid < tm->cur) {
+ tm_fini(tm, 11);
return;
}
+
+ if(groupid > tm->cur)
+ tm->cur = groupid;
+
+ tm->host(tm->tag, &th, groupid);
} else {
tm_fini(tm, 11);
return;
tm->tag = tag;
tm->schedule = nterfacer_sendline("R", "relay", 4, (char *[]){"1", "1", "O", "trustdump #9999999 1"}, tm_stage1, tm);
+ if(!tm->schedule) {
+ nsfree(POOL_TRUSTS, tm);
+ return NULL;
+ }
+
return tm;
}
#include "../core/hooks.h"
#include "../core/error.h"
#include "../core/nsmalloc.h"
+#include "../server/server.h"
#include "trusts.h"
void trusts_registerevents(void);
for(tg=tglist;tg;tg=tg->next)
tg->exts[index] = NULL;
}
+
+int trusts_fullyonline(void) {
+ if(myhub == -1)
+ return 0;
+
+ return serverlist[myhub].linkstate == LS_LINKED;
+}
+
int findtgext(const char *);
int registertgext(const char *);
void releasetgext(int);
+int trusts_fullyonline(void);
/* db.c */
extern int trustsdbloaded;
int trusts_loaddb(void);
void trusts_closedb(int);
-trustgroup *tg_new(char *name, unsigned int trustedfor, int mode, unsigned int maxperident, time_t expires, char *createdby, char *contact, char *comment);
-trusthost *th_new(trustgroup *tg, char *host);
+trustgroup *tg_new(trustgroup *);
+trusthost *th_new(trustgroup *, char *);
+void trustsdb_insertth(char *, trusthost *, unsigned int);
+void trustsdb_inserttg(char *, trustgroup *);
+trustgroup *tg_copy(trustgroup *);
+trusthost *th_copy(trusthost *);
/* formats.c */
char *trusts_timetostr(time_t);
int trusts_parsecidr(const char *, uint32_t *, short *);
int trusts_str2cidr(const char *, uint32_t *, uint32_t *);
char *trusts_cidr2str(uint32_t, uint32_t);
+char *dumpth(trusthost *, int);
+char *dumptg(trustgroup *, int);
+int parseth(char *, trusthost *, unsigned int *, int);
+int parsetg(char *, trustgroup *, int);
+char *rtrim(char *);
/* data.c */
extern trustgroup *tglist;
trustgroup *tg_getbyid(unsigned int);
void th_free(trusthost *);
-trusthost *th_add(trustgroup *, unsigned int, char *, unsigned int, time_t);
+trusthost *th_add(trusthost *);
void tg_free(trustgroup *);
-trustgroup *tg_add(unsigned int, char *, unsigned int, int, unsigned int, unsigned int, time_t, time_t, time_t, char *, char *, char *);
+trustgroup *tg_add(trustgroup *);
trusthost *th_getbyhost(uint32_t);
trusthost *th_getbyhostandmask(uint32_t, uint32_t);
trusthost *th_getsmallestsupersetbyhost(uint32_t, uint32_t);
void th_linktree(void);
unsigned int nexttgmarker(void);
unsigned int nextthmarker(void);
+trustgroup *tg_inttotg(unsigned int);
/* migration.c */
-typedef void (*TrustMigrationGroup)(void *, unsigned int, char *, unsigned int, unsigned int, unsigned int, unsigned int, time_t, time_t, time_t, char *, char *, char *);
-typedef void (*TrustMigrationHost)(void *, unsigned int, char *, unsigned int, time_t);
+typedef void (*TrustMigrationGroup)(void *, trustgroup *);
+typedef void (*TrustMigrationHost)(void *, trusthost *, unsigned int);
typedef void (*TrustMigrationFini)(void *, int);
typedef struct trustmigration {
#include "../control/control.h"
#include "../lib/irc_string.h"
#include "../lib/strlfunc.h"
+#include "../core/nsmalloc.h"
#include "trusts.h"
static void registercommands(int, void *);
}
}
+static void insertth(array *parents, trusthost *th) {
+ int i;
+ trusthost **p2 = (trusthost **)(parents->content);
+
+ /* this eliminates common subtrees */
+ for(i=0;i<parents->cursi;i++)
+ if(p2[i] == th)
+ break;
+
+ if(i == parents->cursi) {
+ int pos = array_getfreeslot(parents);
+ ((trusthost **)(parents->content))[pos] = th;
+ }
+}
+
static void marktree(array *parents, unsigned int marker, trusthost *th) {
trusthost *pth;
+ int parentcount = 0;
for(pth=th->parent;pth;pth=pth->next) {
- trusthost **p2 = (trusthost **)(parents->content);
- int i;
-
- /* this eliminates common subtrees */
- for(i=0;i<parents->cursi;i++)
- if(p2[i] == pth)
- break;
-
- if(i == parents->cursi) {
- int pos = array_getfreeslot(parents);
- ((trusthost **)(parents->content))[pos] = pth;
- }
+ insertth(parents, pth);
pth->marker = marker;
}
+ if(parentcount == 0)
+ insertth(parents, th);
+
/* sadly we need to recurse down */
traverseandmark(marker, th);
}
snprintf(parentbuf, sizeof(parentbuf), "%-10d %s", th->group->id, th->group->name->content);
}
- controlreply(np, "%s%s%s %-10d %-10d %-20s%s", prespacebuf, cidrstr, postspacebuf, th->count, th->maxusage, (th->count>0)?"(now)":((th->lastseen>0)?trusts_timetostr(th->lastseen):"(never)"), parentbuf);
+ controlreply(np, "%s%s%s %-10d %-10d %-21s%s", prespacebuf, cidrstr, postspacebuf, th->count, th->maxusage, (th->count>0)?"(now)":((th->lastseen>0)?trusts_timetostr(th->lastseen):"(never)"), parentbuf);
for(th=th->children;th;th=th->nextbychild)
outputtree(np, marker, originalgroup, th, depth + 1);
controlreply(sender, "Max usage : %d", tg->maxusage);
controlreply(sender, "Last max reset : %s", tg->lastmaxuserreset?trusts_timetostr(tg->lastmaxuserreset):"(never)");
- controlreply(sender, "Host Current Max Last seen Group ID Group name");
+ controlreply(sender, "Host Current Max Last seen Group ID Group name");
marker = nextthmarker();
array_init(&parents, sizeof(trusthost *));
return CMD_OK;
}
+static int comparetgs(const void *_a, const void *_b) {
+ const trustgroup *a = _a;
+ const trustgroup *b = _b;
+
+ if(a->id > b->id)
+ return 1;
+ if(a->id < b-> id)
+ return -1;
+ return 0;
+}
+
+static int trusts_cmdtrustdump(void *source, int argc, char **argv) {
+ trusthost *th;
+ trustgroup *tg, **atg;
+ unsigned int wanted, max, maxid, totalcount, i, groupcount, linecount;
+ nick *np = source;
+
+ if((argc < 2) || (argv[0][0] != '#'))
+ return CMD_USAGE;
+
+ wanted = atoi(&argv[0][1]);
+ max = atoi(argv[1]);
+
+ for(maxid=totalcount=0,tg=tglist;tg;tg=tg->next) {
+ if(totalcount == 0 || tg->id > maxid)
+ maxid = tg->id;
+
+ totalcount++;
+ }
+
+ if(maxid > totalcount) {
+ controlreply(np, "Start ID cannot exceed current maximum group ID (#%u)", maxid);
+ return CMD_OK;
+ }
+
+ atg = nsmalloc(POOL_TRUSTS, sizeof(trusthost *) * totalcount);
+ if(!atg) {
+ controlreply(np, "Memory error.");
+ return CMD_ERROR;
+ }
+
+ for(i=0,tg=tglist;i<totalcount&&th;tg=tg->next,i++)
+ atg[i] = tg;
+
+ qsort(atg, totalcount, sizeof(trustgroup *), comparetgs);
+
+ for(i=0;i<totalcount;i++)
+ if(atg[i]->id >= wanted)
+ break;
+
+ for(groupcount=linecount=0;i<totalcount;i++) {
+ linecount++;
+ groupcount++;
+
+ controlreply(np, "G,%s", dumptg(atg[i], 1));
+
+ for(th=atg[i]->hosts;th;th=th->next) {
+ linecount++;
+ controlreply(np, "H,%s", dumpth(th, 1));
+ }
+
+ if(--max == 0)
+ break;
+ }
+ nsfree(POOL_TRUSTS, atg);
+
+ controlreply(np, "End of list, %u groups and %u lines returned.", groupcount, linecount);
+ return CMD_OK;
+}
+
static int commandsregistered;
static void registercommands(int hooknum, void *arg) {
commandsregistered = 1;
registercontrolhelpcmd("trustlist", NO_OPER, 1, trusts_cmdtrustlist, "Usage: trustlist <#id|name|id>\nShows trust data for the specified trust group.");
+ registercontrolhelpcmd("trustdump", NO_OPER, 2, trusts_cmdtrustdump, "Usage: trustdump <#id> <number>");
}
static void deregistercommands(int hooknum, void *arg) {
commandsregistered = 0;
deregistercontrolcmd("trustlist", trusts_cmdtrustlist);
+ deregistercontrolcmd("trustdump", trusts_cmdtrustdump);
}
void _init(void) {
}
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(!trusts_str2cidr(host, &th.ip, &th.mask)) {
+ Error("trusts", ERR_WARNING, "Error parsing cidr for host: %s", host);
+ continue;
+ }
+
+ th.maxusage = strtoul(result->get(result, 3), NULL, 10);
+ th.lastseen = (time_t)strtoul(result->get(result, 4), 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.mode = 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.lastmaxuserreset = (time_t)strtoul(result->get(result, 8), NULL, 10);
+ tg.createdby = getsstring(rtrim(result->get(result, 9)), NICKLEN);
+ 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");
if(!trustsdb) {
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 = th_add(tg, thmaxid + 1, host, 0, 0);
+ th_getsuperandsubsets(ith->ip, ith->mask, &superset, &subset);
+ th_adjusthosts(th, subset, superset);
+ th_linktree();
+
+ return th;
+}
+
+trusthost *th_new(trustgroup *tg, char *host) {
+ trusthost *th, nth;
+
+ if(!trusts_str2cidr(host, &nth.ip, &nth.mask))
+ return NULL;
+
+ nth.group = tg;
+ nth.id = thmaxid + 1;
+ nth.lastseen = 0;
+ nth.maxusage = 0;
+
+ 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->lastmaxuserreset = 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, lastseen) VALUES (?, ?, ?, ?, ?)",
+ "Tuusut", table, th->id, groupid, trusts_cidr2str(th->ip, th->mask), th->maxusage, th->lastseen
);
+}
- return tg;
+void trustsdb_inserttg(char *table, trustgroup *tg) {
+ trustsdb->squery(trustsdb,
+ "INSERT INTO ? (id, name, trustedfor, mode, maxperident, maxusage, expires, lastseen, lastmaxuserreset, createdby, contact, comment) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
+ "Tusuuuutttsss", table, 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
+ );
}
void _init(void) {
- trusts_loaddb();
+ trusts_connectdb();
}
void _fini(void) {
#include "../control/control.h"
#include "../lib/irc_string.h"
#include "../lib/strlfunc.h"
+#include "../core/config.h"
#include "trusts.h"
static void registercommands(int, void *);
}
controlreply(sender, "Host added.");
+ triggerhook(HOOK_TRUSTS_ADDHOST, th);
+
/* TODO: controlwall */
return CMD_OK;
char *name, *contact, *comment, createdby[ACCOUNTLEN + 2];
unsigned int howmany, maxperident, enforceident;
time_t howlong;
- trustgroup *tg;
+ trustgroup *tg, itg;
if(cargc < 6)
return CMD_USAGE;
snprintf(createdby, sizeof(createdby), "#%s", sender->authname);
- tg = tg_new(name, howmany, enforceident, maxperident, howlong + time(NULL), createdby, contact, comment);
+ itg.trustedfor = howmany;
+ itg.mode = enforceident;
+ itg.maxperident = maxperident;
+ itg.expires = howlong + time(NULL);
+ itg.createdby = getsstring(createdby, NICKLEN);
+ itg.contact = getsstring(contact, CONTACTLEN);
+ itg.comment = getsstring(comment, COMMENTLEN);
+ itg.name = getsstring(name, TRUSTNAMELEN);
+
+ if(itg.createdby && itg.contact && itg.comment && itg.name) {
+ tg = tg_new(&itg);
+ } else {
+ tg = NULL;
+ }
+
+ freesstring(itg.createdby);
+ freesstring(itg.comment);
+ freesstring(itg.name);
+ freesstring(itg.contact);
+
if(!tg) {
controlreply(sender, "An error occured adding the trustgroup.");
return CMD_ERROR;
}
controlreply(sender, "Group added.");
+ triggerhook(HOOK_TRUSTS_ADDGROUP, tg);
+
/* TODO: controlwall */
return CMD_OK;
deregistercontrolcmd("trustadd", trusts_cmdtrustadd);
}
+static int loaded;
+
void _init(void) {
+ sstring *m;
+
+ m = getconfigitem("trusts", "master");
+ if(!m || (atoi(m->content) != 1)) {
+ Error("trusts_management", ERR_ERROR, "Not a master server, not loaded.");
+ return;
+ }
+
+ loaded = 1;
+
registerhook(HOOK_TRUSTS_DB_LOADED, registercommands);
registerhook(HOOK_TRUSTS_DB_CLOSED, deregistercommands);
}
void _fini(void) {
+ if(!loaded)
+ return;
+
deregisterhook(HOOK_TRUSTS_DB_LOADED, registercommands);
deregisterhook(HOOK_TRUSTS_DB_CLOSED, deregistercommands);
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
#include "../core/hooks.h"
+#include "../core/config.h"
+#include "../core/error.h"
+#include "../lib/sha1.h"
+#include "../lib/hmac.h"
+#include "../xsb/xsb.h"
+#include "../control/control.h"
#include "trusts.h"
-static int commandsregistered;
-static void registercommands(int hooknum, void *arg) {
+static void broadcast(SHA1_CTX *c, unsigned int replicationid, unsigned int lineno, char *command, char *format, ...) {
+ char buf[512], buf2[600];
+ va_list va;
+ int len;
+
+ va_start(va, format);
+ vsnprintf(buf, sizeof(buf), format, va);
+ va_end(va);
+
+ len = snprintf(buf2, sizeof(buf2), "%u %u %s", replicationid, lineno, buf);
+ xsb_broadcast(command, NULL, "%s", buf2);
+
+ if(len > (sizeof(buf2) - 1))
+ len = sizeof(buf2) - 1;
+ if(len < 0)
+ len = 0;
+
+ buf2[len] = '\n';
+
+ SHA1Update(c, (unsigned char *)buf2, len + 1);
+}
+
+static void replicate(int forced) {
+ SHA1_CTX s;
+ unsigned int lineno, lines;
+ unsigned char digest[SHA1_DIGESTSIZE];
+ char digestbuf[SHA1_DIGESTSIZE*2+1];
+ static unsigned int replicationid = 0;
+ trustgroup *tg;
+ trusthost *th;
+
+ if(++replicationid > 10000)
+ replicationid = 1;
+
+ for(lines=2,tg=tglist;tg;tg=tg->next) {
+ lines++;
+ for(th=tg->hosts;th;th=th->next)
+ lines++;
+ }
+
+ SHA1Init(&s);
+ lineno = 1;
+ broadcast(&s, replicationid, lineno++, "trinit", "%d %u", forced, lines);
+
+ for(tg=tglist;tg;tg=tg->next) {
+ broadcast(&s, replicationid, lineno++, "trdata", "G %s", dumptg(tg, 0));
+
+ for(th=tg->hosts;th;th=th->next)
+ broadcast(&s, replicationid, lineno++, "trdata", "H %s", dumpth(th, 0));
+ }
+
+ SHA1Final(digest, &s);
+ xsb_broadcast("trfini", NULL, "%u %u %s", replicationid, lineno, hmac_printhex(digest, digestbuf, SHA1_DIGESTSIZE));
+}
+
+static int xsb_tr_requeststart(void *source, int argc, char **argv) {
+ static time_t last = 0;
+ time_t t = time(NULL);
+
+ if(t - last > 5) {
+ last = t;
+
+ replicate(0);
+ }
+
+ return CMD_OK;
+}
+
+static void groupadded(int hooknum, void *arg) {
+ trustgroup *tg = arg;
+
+ xsb_broadcast("traddgroup", NULL, "%s", dumptg(tg, 0));
+}
+
+static void groupremoved(int hooknum, void *arg) {
+ trustgroup *tg = arg;
+
+ xsb_broadcast("trdelgroup", NULL, "%u", tg->id);
+}
+
+static void hostadded(int hooknum, void *arg) {
+ trusthost *th = arg;
+
+ xsb_broadcast("traddhost", NULL, "%s", dumpth(th, 0));
+}
+
+static void hostremoved(int hooknum, void *arg) {
+ trusthost *th = arg;
+
+ xsb_broadcast("trdelhost", NULL, "%u", th->id);
+}
+
+static int trusts_cmdtrustforceresync(void *source, int argc, char **argv) {
+ nick *np = source;
+
+ controlreply(np, "Resync in progress. . .");
+ replicate(1);
+ controlreply(np, "Resync complete.");
+
+ return CMD_OK;
+}
+
+static int commandsregistered, loaded;
+static void __dbloaded(int hooknum, void *arg) {
if(commandsregistered)
return;
+
commandsregistered = 1;
- /* do init stuff here */
+ xsb_addcommand("trrequeststart", 0, xsb_tr_requeststart);
+
+ registerhook(HOOK_TRUSTS_ADDGROUP, groupadded);
+ registerhook(HOOK_TRUSTS_DELGROUP, groupremoved);
+ registerhook(HOOK_TRUSTS_ADDHOST, hostadded);
+ registerhook(HOOK_TRUSTS_DELGROUP, hostremoved);
+
+ /* we've just reloaded */
+ /* if we're not online, no problem, other nodes will ask us individually */
+ if(trusts_fullyonline())
+ replicate(1);
+
+ registercontrolhelpcmd("trustforceresync", NO_DEVELOPER, 0, trusts_cmdtrustforceresync, "Usage: trustforceresync");
}
-static void deregistercommands(int hooknum, void *arg) {
+static void __dbclosed(int hooknum, void *arg) {
if(!commandsregistered)
return;
commandsregistered = 0;
- /* do fini stuff here */
+ xsb_delcommand("trrequeststart", xsb_tr_requeststart);
+
+ registerhook(HOOK_TRUSTS_ADDGROUP, groupadded);
+ registerhook(HOOK_TRUSTS_DELGROUP, groupremoved);
+ registerhook(HOOK_TRUSTS_ADDHOST, hostadded);
+ registerhook(HOOK_TRUSTS_DELGROUP, hostremoved);
+
+ deregistercontrolcmd("trustforceresync", trusts_cmdtrustforceresync);
}
void _init(void) {
- registerhook(HOOK_TRUSTS_DB_LOADED, registercommands);
- registerhook(HOOK_TRUSTS_DB_CLOSED, deregistercommands);
+ sstring *m;
+
+ m = getconfigitem("trusts", "master");
+ if(!m || (atoi(m->content) != 1)) {
+ Error("trusts_master", ERR_ERROR, "Not a master server, not loaded.");
+ return;
+ }
- if(trustsdbloaded)
- registercommands(0, NULL);
+ loaded = 1;
+
+ registerhook(HOOK_TRUSTS_DB_LOADED, __dbloaded);
+ registerhook(HOOK_TRUSTS_DB_CLOSED, __dbclosed);
+
+ if(trustsdbloaded) {
+ /* this will force a sync if we're online */
+ /* if we're not we'll be asked to sync when we come online */
+ __dbloaded(0, NULL);
+ } else {
+ if(!trusts_loaddb())
+ Error("trusts_master", ERR_ERROR, "Unable to load database.");
+
+ /* do nothing else, other servers will ask us when we come online */
+ /* also the __dbloaded hook will be triggered */
+ }
}
void _fini(void) {
- deregisterhook(HOOK_TRUSTS_DB_LOADED, registercommands);
- deregisterhook(HOOK_TRUSTS_DB_CLOSED, deregistercommands);
+ if(!loaded)
+ return;
+
+ deregisterhook(HOOK_TRUSTS_DB_LOADED, __dbloaded);
+ deregisterhook(HOOK_TRUSTS_DB_CLOSED, __dbclosed);
+
+ trusts_closedb(0);
- deregistercommands(0, NULL);
+ __dbclosed(0, NULL);
}
#include "../control/control.h"
#include "../lib/irc_string.h"
+#include "../core/config.h"
#include "trusts.h"
int trusts_migration_start(TrustDBMigrationCallback, void *);
deregistercontrolcmd("trustmigrate", trusts_cmdmigrate);
}
+static int loaded = 0;
void _init(void) {
+ sstring *m;
+
+ m = getconfigitem("trusts", "master");
+ if(!m || (atoi(m->content) != 1)) {
+ Error("trusts_migrationr", ERR_ERROR, "Not a master server, not loaded.");
+ return;
+ }
+
+ loaded = 1;
+
registerhook(HOOK_TRUSTS_DB_LOADED, registercommands);
registerhook(HOOK_TRUSTS_DB_CLOSED, deregistercommands);
}
void _fini(void) {
+ if(!loaded)
+ return;
+
deregisterhook(HOOK_TRUSTS_DB_LOADED, registercommands);
deregisterhook(HOOK_TRUSTS_DB_CLOSED, deregistercommands);
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
#include "../core/hooks.h"
+#include "../core/config.h"
+#include "../core/error.h"
+#include "../control/control.h"
+#include "../xsb/xsb.h"
+#include "../lib/sha1.h"
+#include "../lib/hmac.h"
+#include "../lib/irc_string.h"
+#include "../core/schedule.h"
+#include "../server/server.h"
#include "trusts.h"
-static int commandsregistered;
-static void registercommands(int hooknum, void *arg) {
- if(commandsregistered)
- return;
- commandsregistered = 1;
+static int syncing, synced;
+static sstring *masterserver;
+
+static unsigned int curlineno, totallines;
+static SHA1_CTX s;
+
+void trusts_replication_createtables(void);
+void trusts_replication_swap(void);
+void trusts_replication_complete(int);
+
+static void __abandonreplication(const char *fn, int line, char *error, ...) {
+ va_list ap;
+ char buf[512], buf2[600];
+
+ va_start(ap, error);
+ vsnprintf(buf, sizeof(buf), "%s", ap);
+ va_end(ap);
+
+ snprintf(buf2, sizeof(buf2), "Error replicating (function: %s, line: %d): %s", fn, line, buf);
+
+ Error("trusts_slave", ERR_ERROR, "%s", buf2);
- /* do init stuff here */
+ syncing = 0;
+
+ /* TODO: warn IRC */
}
-static void deregistercommands(int hooknum, void *arg) {
- if(!commandsregistered)
+#define abandonreplication(x, ...) __abandonreplication(__FUNCTION__, __LINE__, x , # __VA_ARGS__)
+
+void trusts_replication_complete(int error) {
+ if(error) {
+ abandonreplication("final replication stage: error %d", error);
+ return;
+ }
+ Error("trusts_slave", ERR_INFO, "Replication complete!");
+
+ if(!trusts_loaddb()) {
+ abandonreplication("couldn't load database");
return;
- commandsregistered = 0;
+ }
+
+ synced = 1;
+}
+
+static char *extractline(char *buf, int reset, int update, int final) {
+ unsigned char n = '\n';
+ int chars = 0;
+ unsigned int lineno, id;
+ static unsigned int curid;
+
+ if(sscanf(buf, "%u %u %n", &id, &lineno, &chars) != 2) {
+ abandonreplication("bad number for sscanf result");
+ return NULL;
+ }
+
+ if(chars <= 0) {
+ abandonreplication("bad number of characters");
+ return NULL;
+ }
+
+ if(reset && (lineno != 1)) {
+ abandonreplication("bad initial line number");
+ return NULL;
+ }
+
+ if(update) {
+ if(reset) {
+ curlineno = 2;
+ curid = id;
+ SHA1Init(&s);
+ } else {
+ /* will happen if two are sent at once, but that's ok */
+ if(id != curid)
+ return NULL;
+
+ if(lineno != curlineno) {
+ abandonreplication("unexpected line number");
+ Error("trusts_slave", ERR_ERROR, "Didn't get expected line number (%u vs. %u).", lineno, curlineno);
+ return NULL;
+ }
+ if(lineno > totallines) {
+ abandonreplication("too many lines");
+ Error("trusts_slave", ERR_ERROR, "Too many lines received!");
+ return NULL;
+ }
+
+ curlineno++;
+
+ }
+
+ if(!final) {
+ SHA1Update(&s, (unsigned char *)buf, strlen(buf));
+ SHA1Update(&s, &n, 1);
+ }
+ }
+
+ return &buf[chars];
+}
+
+/* trinit id lineno force totallines */
+static int xsb_trinit(void *source, int argc, char **argv) {
+ char *buf;
+ unsigned int forced;
+
+ if(argc < 1) {
+ abandonreplication("bad number of args");
+ return CMD_ERROR;
+ }
+
+ buf = extractline(argv[0], 1, 0, 1);
+ if(!buf)
+ return CMD_ERROR;
+
+ if((sscanf(buf, "%u %u", &forced, &totallines) != 2)) {
+ abandonreplication("bad number for sscanf result");
+ return CMD_ERROR;
+ }
+
+ if(totallines < 2) {
+ abandonreplication("bad number of lines");
+ return CMD_ERROR;
+ }
+
+ if(!forced || synced)
+ return CMD_OK;
+
+ if(!extractline(argv[0], 1, 1, 0))
+ return CMD_ERROR;
+
+ trusts_replication_createtables();
+
+ syncing = 1;
+
+ Error("trusts_slave", ERR_INFO, "Replication in progress. . .");
+ return CMD_OK;
+}
+
+/* trdata id lines type data */
+static int xsb_trdata(void *source, int argc, char **argv) {
+ char *buf;
+
+ if(!syncing)
+ return CMD_OK;
+
+ if(argc < 1) {
+ abandonreplication("bad number of args");
+ return CMD_ERROR;
+ }
+
+ buf = extractline(argv[0], 0, 1, 0);
+ if(!buf)
+ return CMD_ERROR;
+
+ if(buf[0] && (buf[1] == ' ')) {
+ if(buf[0] == 'G') {
+ trustgroup tg;
+ if(!parsetg(&buf[2], &tg, 0)) {
+ abandonreplication("bad trustgroup line");
+ Error("trusts_slave", ERR_ERROR, "Bad trustgroup line: %s", buf);
+ return CMD_ERROR;
+ }
+ trustsdb_inserttg("replication_groups", &tg);
+
+ freesstring(tg.name);
+ freesstring(tg.createdby);
+ freesstring(tg.contact);
+ freesstring(tg.comment);
+
+ } else if(buf[0] == 'H') {
+ unsigned int tgid;
+ trusthost th;
+
+ if(!parseth(&buf[2], &th, &tgid, 0)) {
+ abandonreplication("bad trusthost line");
+ Error("trusts_slave", ERR_ERROR, "Bad trusthost line: %s", buf);
+ return CMD_ERROR;
+ }
+ trustsdb_insertth("replication_hosts", &th, tgid);
+ } else {
+ abandonreplication("bad trust type");
+
+ Error("trusts_slave", ERR_ERROR, "Bad trust type: %c", buf[0]);
+ return CMD_ERROR;
+ }
+ } else {
+ abandonreplication("malformed line");
+
+ Error("trusts_slave", ERR_ERROR, "Malformed data line: %s", buf);
+ }
+
+ return CMD_OK;
+}
+
+/* trfini id lines sha */
+static int xsb_trfini(void *source, int argc, char **argv) {
+ char *buf, digestbuf[SHA1_DIGESTSIZE * 2 + 1];
+ unsigned char digest[SHA1_DIGESTSIZE];
+
+ if(!syncing)
+ return CMD_OK;
+
+ if(argc < 1) {
+ abandonreplication("bad number of args");
+ return CMD_ERROR;
+ }
+
+ buf = extractline(argv[0], 0, 1, 1);
+ if(!buf)
+ return CMD_ERROR;
+
+ if((totallines + 1) != curlineno) {
+ abandonreplication("wrong number of lines received");
+ Error("trusts_slave", ERR_ERROR, "Wrong number of lines received (%u vs. %u).", totallines, curlineno - 1);
+ return CMD_ERROR;
+ }
+
+ SHA1Final(digest, &s);
+ if(strcasecmp(hmac_printhex(digest, digestbuf, SHA1_DIGESTSIZE), buf)) {
+ abandonreplication("digest mismatch");
+ Error("trusts_slave", ERR_ERROR, "Digest mismatch.");
+ return CMD_ERROR;
+ }
- /* do fini stuff here */
+ Error("trusts_slave", ERR_INFO, "Data verification successful.");
+
+ trusts_replication_swap();
+
+ synced = 1;
+
+ return CMD_OK;
+}
+
+static int xsb_traddgroup(void *source, int argc, char **argv) {
+ trustgroup tg, *otg;
+
+ if(!synced)
+ return CMD_OK;
+
+ if(argc < 1) {
+ abandonreplication("bad number of arguments");
+ return CMD_ERROR;
+ }
+
+ if(!parsetg(argv[0], &tg, 0)) {
+ abandonreplication("bad trustgroup line");
+ Error("trusts_slave", ERR_ERROR, "Bad trustgroup line: %s", argv[0]);
+ return CMD_ERROR;
+ }
+
+ otg = tg_copy(&tg);
+
+ freesstring(tg.name);
+ freesstring(tg.createdby);
+ freesstring(tg.contact);
+ freesstring(tg.comment);
+
+ if(!otg) {
+ abandonreplication("unable to add trustgroup");
+ return CMD_ERROR;
+ }
+
+ return CMD_OK;
+}
+
+static int xsb_traddhost(void *source, int argc, char **argv) {
+ unsigned int tgid;
+ trusthost th;
+
+ if(!synced)
+ return CMD_OK;
+
+ if(argc < 1) {
+ abandonreplication("bad number of arguments");
+ return CMD_ERROR;
+ }
+
+ if(!parseth(argv[0], &th, &tgid, 0)) {
+ abandonreplication("bad trusthost line");
+ Error("trusts_slave", ERR_ERROR, "Bad trusthost line: %s", argv[0]);
+ return CMD_ERROR;
+ }
+
+ th.group = tg_inttotg(tgid);
+ if(!th.group) {
+ abandonreplication("unable to lookup trustgroup");
+ return CMD_ERROR;
+ }
+
+ if(!th_copy(&th)) {
+ abandonreplication("unable to add trusthost");
+ return CMD_ERROR;
+ }
+
+ return CMD_OK;
+}
+
+static int xsb_trdelhost(void *source, int argc, char **argv) {
+ if(!synced)
+ return CMD_OK;
+
+ if(argc < 1) {
+ abandonreplication("bad number of arguments");
+ return CMD_ERROR;
+ }
+
+ return CMD_OK;
+}
+
+static int xsb_trdelgroup(void *source, int argc, char **argv) {
+ if(!synced)
+ return CMD_OK;
+
+ if(argc < 1) {
+ abandonreplication("bad number of arguments");
+ return CMD_ERROR;
+ }
+
+ return CMD_OK;
+}
+
+static int trusts_cmdtrustresync(void *source, int argc, char **argv) {
+ nick *np = source;
+
+ if(syncing) {
+ controlreply(np, "Synchronisation is already in progress.");
+ return CMD_ERROR;
+ }
+
+ synced = 0;
+ xsb_broadcast("trrequestsync", NULL, "%s", "");
+ controlreply(np, "Synchronisation request sent.");
+
+ return CMD_OK;
+}
+
+static int loaded;
+static void *syncsched;
+
+static void checksynced(void *arg) {
+ if(!synced || !syncing)
+ xsb_broadcast("trrequestsync", NULL, "%s", "");
+}
+
+static void __serverlinked(int hooknum, void *arg) {
+ int servernum = (int)arg;
+
+ if(!ircd_strcmp(serverlist[servernum].name->content, masterserver->content)) {
+ syncing = synced = 0;
+ xsb_broadcast("trrequestsync", NULL, "%s", "");
+ }
}
void _init(void) {
- registerhook(HOOK_TRUSTS_DB_LOADED, registercommands);
- registerhook(HOOK_TRUSTS_DB_CLOSED, deregistercommands);
+ sstring *m;
- if(trustsdbloaded)
- registercommands(0, NULL);
+ m = getconfigitem("trusts", "master");
+ if(m && (atoi(m->content) != 0)) {
+ Error("trusts_slave", ERR_ERROR, "Not a slave server, not loaded.");
+ return;
+ }
+
+ masterserver = getcopyconfigitem("trusts", "masterserver", "", 255);
+ if(!masterserver || !masterserver->content || !masterserver->content[0]) {
+ Error("trusts_slave", ERR_ERROR, "No master server defined.");
+ freesstring(masterserver);
+ return;
+ }
+
+ loaded = 1;
+
+ registercontrolhelpcmd("trustresync", NO_DEVELOPER, 0, trusts_cmdtrustresync, "Usage: trustresync");
+
+ xsb_addcommand("trinit", 1, xsb_trinit);
+ xsb_addcommand("trdata", 1, xsb_trdata);
+ xsb_addcommand("trfini", 1, xsb_trfini);
+ xsb_addcommand("traddhost", 1, xsb_traddhost);
+ xsb_addcommand("traddgroup", 1, xsb_traddgroup);
+ xsb_addcommand("trdelhost", 1, xsb_trdelhost);
+ xsb_addcommand("trdelgroup", 1, xsb_trdelgroup);
+
+ registerhook(HOOK_SERVER_LINKED, __serverlinked);
+ syncsched = schedulerecurring(time(NULL)+5, 0, 60, checksynced, NULL);
+
+ if(trusts_fullyonline())
+ xsb_broadcast("trrequestsync", NULL, "%s", "");
}
void _fini(void) {
- deregisterhook(HOOK_TRUSTS_DB_LOADED, registercommands);
- deregisterhook(HOOK_TRUSTS_DB_CLOSED, deregistercommands);
+ if(!loaded)
+ return;
+
+ freesstring(masterserver);
+
+ deregistercontrolcmd("trustresync", trusts_cmdtrustresync);
+
+ xsb_delcommand("trinit", xsb_trinit);
+ xsb_delcommand("trdata", xsb_trdata);
+ xsb_delcommand("trfini", xsb_trfini);
+ xsb_delcommand("traddhost", xsb_traddhost);
+ xsb_delcommand("traddgroup", xsb_traddgroup);
+ xsb_delcommand("trdelhost", xsb_trdelhost);
+ xsb_delcommand("trdelgroup", xsb_trdelgroup);
+
+ deregisterhook(HOOK_SERVER_LINKED, __serverlinked);
+
+ deleteschedule(syncsched, checksynced, NULL);
- deregistercommands(0, NULL);
+ trusts_closedb(0);
}