Add initial wotsap file generation tool
authorJonathan McDowell <noodles@earth.li>
Mon, 30 Sep 2013 14:18:31 +0000 (15:18 +0100)
committerJonathan McDowell <noodles@earth.li>
Mon, 30 Sep 2013 14:24:53 +0000 (15:24 +0100)
Wotsap (http://www.lysator.liu.se/~jc/wotsap/) is a web of trust
statistics and pathfinding tool. It takes a set of preformatted key
data covering the primary UID and signatures on each key.

This commit adds a tool which will generate the file data required for
wotsap. These files still need ar/bzip2 run against them in order to
be fed into wotsap, but are generated from the live keyring data.

.gitignore
Makefile.in
wotsap.c [new file with mode: 0644]

index d7e1c664bf76737223fc00df70667922ad770372..6a7382ca2188b724304c3468fa0a6e88fc03af7f 100644 (file)
@@ -18,6 +18,7 @@ sixdegrees
 splitkeys
 stripkey
 testparse
+wotsap
 tags
 .depend
 autom4te.cache
index b5b8a55ed27c4df350618e63c5ecd13ceeddfe67..ead45eb8fb9f1e4ea3c5880a8fb6ea3d41b5ca32 100644 (file)
@@ -16,7 +16,8 @@ MAKEDEPEND = $(CC) -MM
 prefix ?= @prefix@
 exec_prefix ?= @exec_prefix@
 
-PROGS = add lookup hashquery gpgwww onak splitkeys onak-mail.pl stripkey
+PROGS = add lookup hashquery gpgwww onak splitkeys onak-mail.pl stripkey \
+       wotsap
 CORE_OBJS = armor.o charfuncs.o decodekey.o getcgi.o hash.o marshal.o \
        keyid.o keyindex.o ll.o mem.o onak-conf.o parsekey.o sigcheck.o \
        log.o photoid.o wordlist.o cleanup.o merge.o sendsync.o keyarray.o
@@ -49,7 +50,7 @@ endif
 OBJS = stats.o cleankey.o $(CORE_OBJS) $(KEYDB_OBJ)
 
 all: .depend $(PROGS) testparse maxpath sixdegrees splitkeys onak.conf \
-       $(BACKENDS)
+       wotsap $(BACKENDS)
 
 test: onak $(BACKENDS)
        @./runtests
@@ -105,6 +106,10 @@ sixdegrees: sixdegrees.o $(OBJS)
        $(CC) $(LDFLAGS) -o sixdegrees sixdegrees.o $(OBJS) $(LIBS) \
                $(PROGS_LDFLAGS_EXTRA)
 
+wotsap: wotsap.o $(OBJS)
+       $(CC) $(LDFLAGS) -o wotsap wotsap.o $(OBJS) $(LIBS) \
+               $(PROGS_LDFLAGS_EXTRA)
+
 stripkey: stripkey.o $(OBJS)
        $(CC) $(LDFLAGS) -o stripkey stripkey.o $(OBJS) $(LIBS) \
                $(PROGS_LDFLAGS_EXTRA)
@@ -152,7 +157,7 @@ clean:
        $(RM) $(PROGS) $(OBJS) Makefile.bak testparse maxpath *.core core \
                gpgwww.o add.o lookup.o main.o maxpath.o onak.o sixdegrees \
                sixdegrees.o splitkeys.o stripkey.o onak.conf keyd.o \
-               keydctl.o hashquery.o version.h \
+               keydctl.o hashquery.o wotsap.o version.h \
                TAGS cscope.out cscope.files \
                $(foreach be,@BACKENDS@,keydb_$(be).o) *.so
 ifeq (x@KEYD@, xyes)
diff --git a/wotsap.c b/wotsap.c
new file mode 100644 (file)
index 0000000..339b949
--- /dev/null
+++ b/wotsap.c
@@ -0,0 +1,205 @@
+/*
+ * wotsap.c - Output a set of wotsap files from an onak keyring
+ *
+ * See:
+ *
+ * http://www.lysator.liu.se/~jc/wotsap/wotfileformat.txt
+ *
+ * for more details of the format.
+ *
+ * Copyright 2013 Jonathan McDowell <noodles@earth.li>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <getopt.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+#include "hash.h"
+#include "log.h"
+#include "onak-conf.h"
+#include "stats.h"
+#include "version.h"
+
+static struct ll *sortkeyll(struct ll *keys)
+{
+       struct ll *newll, *tmp, **curobj;
+       struct stats_key *curkey, *toadd;
+
+       newll = NULL;
+       while (keys) {
+               toadd = (struct stats_key *) keys->object;
+               curobj = &newll;
+               while (*curobj) {
+                       curkey = (struct stats_key *) (*curobj)->object;
+                       if (curkey->keyid >= toadd->keyid) {
+                               break;
+                       }
+                       curobj = &((*curobj)->next);
+               }
+
+               tmp = keys->next;
+               if (*curobj == NULL || curkey->keyid != toadd->keyid) {
+                       keys->next = *curobj;
+                       *curobj = keys;
+               }
+               keys = tmp;
+       }
+       return newll;
+}
+
+static void output_key(FILE *names, FILE *keys, uint64_t keyid)
+{
+       fprintf(names, "%s\n", config.dbbackend->keyid2uid(keyid));
+       fprintf(keys, "%c%c%c%c", (int) (keyid >> 24) & 0xFF,
+                       (int) (keyid >> 16) & 0xFF,
+                       (int) (keyid >>  8) & 0xFF,
+                       (int) (keyid      ) & 0xFF);
+}
+
+static void wotsap(uint64_t keyid, char *dir)
+{
+       struct ll *pending, *sigll, *sigsave;
+       uint32_t curidx = 0;
+       struct stats_key *curkey, *addkey;
+       char *uid;
+       FILE *names, *keys, *sigs, *file;
+       char *tmppath;
+       uint32_t sigcount, sigentry;
+
+       /* Length of dir + "/" + "signatures" + NUL */
+       tmppath = malloc(strlen(dir) + 12);
+
+       sprintf(tmppath, "%s/WOTVERSION", dir);
+       file = fopen(tmppath, "w");
+       if (file == NULL) {
+               fprintf(stderr, "Couldn't open %s\n", tmppath);
+               return;
+       }
+       fprintf(file, "0.2\n");
+       fclose(file);
+
+       sprintf(tmppath, "%s/README", dir);
+       file = fopen(tmppath, "w");
+       if (file == NULL) {
+               fprintf(stderr, "Couldn't open %s\n", tmppath);
+               return;
+       }
+       fprintf(file, "This is a Web of Trust archive.\n");
+       fprintf(file, "The file format is documented at:\n");
+       fprintf(file, "  http://www.lysator.liu.se/~jc/wotsap/wotfileformat.txt\n\n");
+       fprintf(file, "This file was generated by onak " ONAK_VERSION " \n");
+       fclose(file);
+
+       sprintf(tmppath, "%s/names", dir);
+       names = fopen(tmppath, "w");
+       if (names == NULL) {
+               fprintf(stderr, "Couldn't open %s\n", tmppath);
+               return;
+       }
+       sprintf(tmppath, "%s/keys", dir);
+       keys = fopen(tmppath, "wb");
+       if (keys == NULL) {
+               fprintf(stderr, "Couldn't open %s\n", tmppath);
+               return;
+       }
+       sprintf(tmppath, "%s/signatures", dir);
+       sigs = fopen(tmppath, "wb");
+       if (sigs == NULL) {
+               fprintf(stderr, "Couldn't open %s\n", tmppath);
+               return;
+       }
+       free(tmppath);
+
+       config.dbbackend->cached_getkeysigs(keyid);
+       curkey = findinhash(keyid);
+       curkey->colour = ++curidx;
+       pending = lladd(NULL, curkey);
+
+       output_key(names, keys, curkey->keyid);
+
+       while (pending != NULL) {
+               curkey = (struct stats_key *) pending->object;
+               sigll = config.dbbackend->cached_getkeysigs(curkey->keyid);
+               sigsave = sigll = sortkeyll(sigll);
+               sigcount = 0;
+               while (sigll != NULL) {
+                       addkey = (struct stats_key *) sigll->object;
+                       if (addkey->colour == 0) {
+                               uid = config.dbbackend->keyid2uid(addkey->keyid);
+                               if (uid != NULL) {
+                                       addkey->colour = ++curidx;
+                                       pending = lladdend(pending, addkey);
+                                       output_key(names, keys, addkey->keyid);
+                               }
+                       }
+                       if (addkey->colour != 0) {
+                               sigcount++;
+                       }
+                       sigll = sigll->next;
+               }
+               /* Now output the signatures */
+               sigcount = htonl(sigcount);
+               fwrite(&sigcount, sizeof (sigcount), 1, sigs);
+               sigll = sigsave;
+               while (sigll != NULL) {
+                       addkey = (struct stats_key *) sigll->object;
+                       if (addkey->colour != 0) {
+                               sigentry = addkey->colour - 1;
+                               /* Pretend it's on the primary UID for now */
+                               sigentry |= 0x40000000;
+                               sigentry = htonl(sigentry);
+                               fwrite(&sigentry, sizeof (sigentry), 1, sigs);
+                       }
+                       sigll = sigll->next;
+               }
+               pending = pending->next;
+       }
+
+       fclose(sigs);
+       fclose(keys);
+       fclose(names);
+}
+
+int main(int argc, char *argv[])
+{
+       int optchar;
+       char *configfile = NULL, *dir = NULL;
+       uint64_t keyid = 0x2DA8B985;
+
+       while ((optchar = getopt(argc, argv, "c:")) != -1 ) {
+               switch (optchar) {
+               case 'c':
+                       configfile = strdup(optarg);
+                       break;
+               }
+       }
+
+       if (optind < argc) {
+               dir = argv[optind];
+       }
+
+       readconfig(configfile);
+       initlogthing("wotsap", config.logfile);
+       config.dbbackend->initdb(true);
+       inithash();
+       wotsap(config.dbbackend->getfullkeyid(keyid), dir ? dir : ".");
+       destroyhash();
+       config.dbbackend->cleanupdb();
+       cleanuplogthing();
+       cleanupconfig();
+}