]> the.earth.li Git - onak.git/blob - wotsap.c
Add ability to drop overly large packets
[onak.git] / wotsap.c
1 /*
2  * wotsap.c - Output a set of wotsap files from an onak keyring
3  *
4  * See:
5  *
6  * http://www.lysator.liu.se/~jc/wotsap/wotfileformat.txt
7  *
8  * for more details of the format.
9  *
10  * Copyright 2013 Jonathan McDowell <noodles@earth.li>
11  *
12  * This program is free software: you can redistribute it and/or modify it
13  * under the terms of the GNU General Public License as published by the Free
14  * Software Foundation; version 2 of the License.
15  *
16  * This program is distributed in the hope that it will be useful, but WITHOUT
17  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19  * more details.
20  *
21  * You should have received a copy of the GNU General Public License along with
22  * this program.  If not, see <https://www.gnu.org/licenses/>.
23  */
24
25 #include <getopt.h>
26 #include <stdint.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <arpa/inet.h>
30
31 #include "hash.h"
32 #include "log.h"
33 #include "onak-conf.h"
34 #include "stats.h"
35 #include "version.h"
36
37 static struct ll *sortkeyll(struct ll *keys)
38 {
39         struct ll *newll, *tmp, **curobj;
40         struct stats_key *curkey, *toadd;
41
42         newll = NULL;
43         while (keys) {
44                 toadd = (struct stats_key *) keys->object;
45                 curobj = &newll;
46                 while (*curobj) {
47                         curkey = (struct stats_key *) (*curobj)->object;
48                         if (curkey->keyid >= toadd->keyid) {
49                                 break;
50                         }
51                         curobj = &((*curobj)->next);
52                 }
53
54                 tmp = keys->next;
55                 if (*curobj == NULL || curkey->keyid != toadd->keyid) {
56                         keys->next = *curobj;
57                         *curobj = keys;
58                 }
59                 keys = tmp;
60         }
61         return newll;
62 }
63
64 static void output_key(struct onak_dbctx *dbctx,
65                 FILE *names, FILE *keys, uint64_t keyid)
66 {
67         fprintf(names, "%s\n", dbctx->keyid2uid(dbctx, keyid));
68         fprintf(keys, "%c%c%c%c", (int) (keyid >> 24) & 0xFF,
69                         (int) (keyid >> 16) & 0xFF,
70                         (int) (keyid >>  8) & 0xFF,
71                         (int) (keyid      ) & 0xFF);
72 }
73
74 static void wotsap(struct onak_dbctx *dbctx, uint64_t keyid, char *dir)
75 {
76         struct ll *pending, *sigll, *sigsave;
77         uint32_t curidx = 0;
78         struct stats_key *curkey, *addkey;
79         char *uid;
80         FILE *names, *keys, *sigs, *file;
81         char *tmppath;
82         uint32_t sigcount, sigentry;
83
84         /* Length of dir + "/" + "signatures" + NUL */
85         tmppath = malloc(strlen(dir) + 12);
86
87         sprintf(tmppath, "%s/WOTVERSION", dir);
88         file = fopen(tmppath, "w");
89         if (file == NULL) {
90                 fprintf(stderr, "Couldn't open %s\n", tmppath);
91                 return;
92         }
93         fprintf(file, "0.2\n");
94         fclose(file);
95
96         sprintf(tmppath, "%s/README", dir);
97         file = fopen(tmppath, "w");
98         if (file == NULL) {
99                 fprintf(stderr, "Couldn't open %s\n", tmppath);
100                 return;
101         }
102         fprintf(file, "This is a Web of Trust archive.\n");
103         fprintf(file, "The file format is documented at:\n");
104         fprintf(file, "  http://www.lysator.liu.se/~jc/wotsap/wotfileformat.txt\n\n");
105         fprintf(file, "This file was generated by onak " ONAK_VERSION " \n");
106         fclose(file);
107
108         sprintf(tmppath, "%s/names", dir);
109         names = fopen(tmppath, "w");
110         if (names == NULL) {
111                 fprintf(stderr, "Couldn't open %s\n", tmppath);
112                 return;
113         }
114         sprintf(tmppath, "%s/keys", dir);
115         keys = fopen(tmppath, "wb");
116         if (keys == NULL) {
117                 fprintf(stderr, "Couldn't open %s\n", tmppath);
118                 return;
119         }
120         sprintf(tmppath, "%s/signatures", dir);
121         sigs = fopen(tmppath, "wb");
122         if (sigs == NULL) {
123                 fprintf(stderr, "Couldn't open %s\n", tmppath);
124                 return;
125         }
126         free(tmppath);
127
128         dbctx->cached_getkeysigs(dbctx, keyid);
129         curkey = findinhash(keyid);
130         curkey->colour = ++curidx;
131         pending = lladd(NULL, curkey);
132
133         output_key(dbctx, names, keys, curkey->keyid);
134
135         while (pending != NULL) {
136                 curkey = (struct stats_key *) pending->object;
137                 sigll = dbctx->cached_getkeysigs(dbctx, curkey->keyid);
138                 sigsave = sigll = sortkeyll(sigll);
139                 sigcount = 0;
140                 while (sigll != NULL) {
141                         addkey = (struct stats_key *) sigll->object;
142                         if (addkey->colour == 0 && !addkey->revoked) {
143                                 uid = dbctx->keyid2uid(dbctx, addkey->keyid);
144                                 if (uid != NULL) {
145                                         /* Force it to be loaded so we know if it's revoked */
146                                         dbctx->cached_getkeysigs(dbctx,
147                                                         addkey->keyid);
148                                         if (!addkey->revoked) {
149                                                 addkey->colour = ++curidx;
150                                                 pending = lladdend(pending, addkey);
151                                                 output_key(dbctx, names, keys,
152                                                         addkey->keyid);
153                                         }
154                                 }
155                         }
156                         if (addkey->colour != 0) {
157                                 sigcount++;
158                         }
159                         sigll = sigll->next;
160                 }
161                 /* Now output the signatures */
162                 sigcount = htonl(sigcount);
163                 fwrite(&sigcount, sizeof (sigcount), 1, sigs);
164                 sigll = sigsave;
165                 while (sigll != NULL) {
166                         addkey = (struct stats_key *) sigll->object;
167                         if (addkey->colour != 0) {
168                                 sigentry = addkey->colour - 1;
169                                 /* Pretend it's on the primary UID for now */
170                                 sigentry |= 0x40000000;
171                                 sigentry = htonl(sigentry);
172                                 fwrite(&sigentry, sizeof (sigentry), 1, sigs);
173                         }
174                         sigll = sigll->next;
175                 }
176                 pending = pending->next;
177         }
178
179         fclose(sigs);
180         fclose(keys);
181         fclose(names);
182 }
183
184 int main(int argc, char *argv[])
185 {
186         int optchar;
187         char *configfile = NULL, *dir = NULL;
188         uint64_t keyid = 0x2DA8B985;
189         struct onak_dbctx *dbctx;
190
191         while ((optchar = getopt(argc, argv, "c:")) != -1 ) {
192                 switch (optchar) {
193                 case 'c':
194                         configfile = strdup(optarg);
195                         break;
196                 }
197         }
198
199         if (optind < argc) {
200                 dir = argv[optind];
201         }
202
203         readconfig(configfile);
204         initlogthing("wotsap", config.logfile);
205         dbctx = config.dbinit(config.backend, true);
206         if (dbctx != NULL) {
207                 inithash();
208                 wotsap(dbctx, dbctx->getfullkeyid(dbctx, keyid),
209                         dir ? dir : ".");
210                 destroyhash();
211                 dbctx->cleanupdb(dbctx);
212         } else {
213                 fprintf(stderr, "Couldn't initialize key database.\n");
214         }
215         cleanuplogthing();
216         cleanupconfig();
217         free(configfile);
218 }