]> jfr.im git - irc/quakenet/newserv.git/commitdiff
Okay, HUGE commit.
authorChris Porter <redacted>
Sun, 5 Oct 2008 07:33:37 +0000 (08:33 +0100)
committerChris Porter <redacted>
Sun, 5 Oct 2008 07:33:37 +0000 (08:33 +0100)
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.

15 files changed:
core/hooks.h
trusts/Makefile.in
trusts/data.c
trusts/db-migration.c
trusts/db-slave.c [new file with mode: 0644]
trusts/formats.c
trusts/migration.c
trusts/trusts.c
trusts/trusts.h
trusts/trusts_commands.c
trusts/trusts_db.c
trusts/trusts_management.c
trusts/trusts_master.c
trusts/trusts_migration.c
trusts/trusts_slave.c

index ab6021d99fcc033c5fb6c6e53f1dbeb4e35bed96..78fdf51ca9afcc25a817290e8220723ff933b616 100644 (file)
 #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
 
index a8a2ee8c4a5cfee173edc1c93d026ea46ec212cd..4e7b6e341dbb6afc56e92608cd0bdddb53f31ee0 100644 (file)
@@ -20,7 +20,7 @@ trusts_management.so: trusts_management.o
 
 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 .
index df943a7ab69092303e7f788e7837815f8511042c..23aaaa76a91138b13f013665641954888873eab8 100644 (file)
@@ -77,25 +77,16 @@ void th_linktree(void) {
         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;
@@ -103,8 +94,8 @@ trusthost *th_add(trustgroup *tg, unsigned int id, char *host, unsigned int maxu
 
   th->marker = 0;
 
-  th->next = tg->hosts;
-  tg->hosts = th;
+  th->next = th->group->hosts;
+  th->group->hosts = th;
 
   return th;
 }
@@ -119,32 +110,24 @@ void tg_free(trustgroup *tg) {
   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));
@@ -429,3 +412,14 @@ unsigned int nextthmarker(void) {
 
   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;
+}
+
index 0ca7eaccae50888a6002371a2dbf8e6dc345ea2b..e8bea9b3720a2345afd03abe5eff3808e9702c13 100644 (file)
@@ -6,13 +6,13 @@
 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;
@@ -54,23 +54,18 @@ void trusts_migration_stop(void) {
   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) {
@@ -81,10 +76,10 @@ 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);
   }
@@ -100,7 +95,7 @@ static void tm_final(void *tag, int errcode) {
   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);
@@ -108,7 +103,7 @@ static void tm_final(void *tag, int errcode) {
   } 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");
diff --git a/trusts/db-slave.c b/trusts/db-slave.c
new file mode 100644 (file)
index 0000000..66561cc
--- /dev/null
@@ -0,0 +1,42 @@
+#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", "");
+}
index a3397df726aa65d29fd8acc4ebf5b780c81ae529..aa427760a3e8bd14bb5b727e2fd136af09be8026 100644 (file)
@@ -1,6 +1,10 @@
 #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;
@@ -69,3 +73,171 @@ char *trusts_timetostr(time_t t) {
   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;
+}
index 578fef8267cd791f00b8a61dea083107855fa315..34139292da0659343a8892cbc810b4bc5d5059ea 100644 (file)
@@ -25,76 +25,6 @@ void migration_stop(trustmigration *tm) {
   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;
@@ -132,34 +62,47 @@ static void tm_stage2(int failure, int linec, char **linev, void *tag) {
 
   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;
@@ -219,5 +162,10 @@ trustmigration *migration_start(TrustMigrationGroup group, TrustMigrationHost ho
   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;
 }
index d2f811aa3e306214a847178b3932d5154c1110b0..c15ea114d33140fc5f6679af63c1137142b4e930 100644 (file)
@@ -3,6 +3,7 @@
 #include "../core/hooks.h"
 #include "../core/error.h"
 #include "../core/nsmalloc.h"
+#include "../server/server.h"
 #include "trusts.h"
 
 void trusts_registerevents(void);
@@ -102,3 +103,11 @@ void releasetgext(int index) {
   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;
+}
+
index 12a84fe97d1eb1bef34e0a5fecb0306995d83626..2d2060e03b3432b8c06b654c0c3b4a56b954e2d9 100644 (file)
@@ -76,27 +76,37 @@ extern int trusts_thext, trusts_nextuserext;
 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);
@@ -108,10 +118,11 @@ trusthost *th_getnextsubsetbyhost(trusthost *th, uint32_t ip, uint32_t mask);
 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 {
index b41bf5ba7e86bfb9488e3743a02d2adac4b126f9..0a2f4e0bcbd0d417dd750a83b2b35c1fef27c278 100644 (file)
@@ -3,6 +3,7 @@
 #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 *);
@@ -40,26 +41,34 @@ static void traverseandmark(unsigned int marker, trusthost *th) {
   }
 }
 
+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);
 }
@@ -83,7 +92,7 @@ static void outputtree(nick *np, unsigned int marker, trustgroup *originalgroup,
     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);
@@ -123,7 +132,7 @@ static int trusts_cmdtrustlist(void *source, int cargc, char **cargv) {
   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 *));
@@ -142,6 +151,76 @@ static int trusts_cmdtrustlist(void *source, int cargc, char **cargv) {
   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) {
@@ -150,6 +229,7 @@ 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) {
@@ -158,6 +238,7 @@ static void deregistercommands(int hooknum, void *arg) {
   commandsregistered = 0;
 
   deregistercontrolcmd("trustlist", trusts_cmdtrustlist);
+  deregistercontrolcmd("trustdump", trusts_cmdtrustdump);
 }
 
 void _init(void) {
index d733b35344b68e2f7dd9668f04c0b66744a28faa..35be76bbd2e399df420f9efe0a6256eb5e3308e7 100644 (file)
@@ -81,29 +81,32 @@ static void loadhosts_data(const DBAPIResult *result, void *tag) {
   }
 
   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);
   }
 
@@ -139,38 +142,35 @@ static void loadgroups_data(const DBAPIResult *result, void *tag) {
   }
 
   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);  
@@ -180,7 +180,7 @@ static void loadgroups_fini(const DBAPIResult *result, void *tag) {
   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) {
@@ -191,6 +191,13 @@ int trusts_loaddb(void) {
 
   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");
@@ -231,50 +238,84 @@ static void tg_dbupdatecounts(trustgroup *tg) {
   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) {
index 9ef733c01e4740b1b20d1491895bf8ddae6f0383..7a31f46ffd62bd79d708ba784e29559305ce996a 100644 (file)
@@ -3,6 +3,7 @@
 #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 *);
@@ -73,6 +74,8 @@ static int trusts_cmdtrustadd(void *source, int cargc, char **cargv) {
   }
 
   controlreply(sender, "Host added.");
+  triggerhook(HOOK_TRUSTS_ADDHOST, th);
+
   /* TODO: controlwall */
 
   return CMD_OK;
@@ -83,7 +86,7 @@ static int trusts_cmdtrustgroupadd(void *source, int cargc, char **cargv) {
   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;
@@ -135,13 +138,34 @@ static int trusts_cmdtrustgroupadd(void *source, int cargc, char **cargv) {
 
   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;
@@ -167,7 +191,19 @@ static void deregistercommands(int hooknum, void *arg) {
   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);
 
@@ -176,6 +212,9 @@ void _init(void) {
 }
 
 void _fini(void) {
+  if(!loaded)
+    return;
+
   deregisterhook(HOOK_TRUSTS_DB_LOADED, registercommands);
   deregisterhook(HOOK_TRUSTS_DB_CLOSED, deregistercommands);
 
index b9d070bed913847ebde0d4571ff3f4493e48cf9f..e992e3bca25eece5c8443890dafd10646f4cd9fe 100644 (file)
+#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);
 }
index 8c6ba88f68cb4689ab9ccdec37b5f79497d94321..73ec6886331c57ea97a38918da63a5b0f49fde52 100644 (file)
@@ -1,5 +1,6 @@
 #include "../control/control.h"
 #include "../lib/irc_string.h"
+#include "../core/config.h"
 #include "trusts.h"
 
 int trusts_migration_start(TrustDBMigrationCallback, void *);
@@ -66,7 +67,18 @@ static void deregistercommands(int hooknum, void *arg) {
   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);
 
@@ -75,6 +87,9 @@ void _init(void) {
 }
 
 void _fini(void) {
+  if(!loaded)
+    return;
+
   deregisterhook(HOOK_TRUSTS_DB_LOADED, registercommands);
   deregisterhook(HOOK_TRUSTS_DB_CLOSED, deregistercommands);
 
index b9d070bed913847ebde0d4571ff3f4493e48cf9f..30eade51d6da5601421188bf315b05832a6cd023 100644 (file)
+#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);
 }