]> the.earth.li Git - onak.git/blob - onak.c
Fix issues found by llvm scan-build static analysis
[onak.git] / onak.c
1 /*
2  * onak.c - An OpenPGP keyserver.
3  *
4  * This is the main swiss army knife binary.
5  *
6  * Copyright 2002 Jonathan McDowell <noodles@earth.li>
7  *
8  * This program is free software: you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License as published by the Free
10  * Software Foundation; version 2 of the License.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License along with
18  * this program; if not, write to the Free Software Foundation, Inc., 51
19  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  */
21
22 #include <fcntl.h>
23 #include <getopt.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <unistd.h>
30
31 #include "armor.h"
32 #include "charfuncs.h"
33 #include "cleankey.h"
34 #include "cleanup.h"
35 #include "keydb.h"
36 #include "keyid.h"
37 #include "keyindex.h"
38 #include "keystructs.h"
39 #include "log.h"
40 #include "mem.h"
41 #include "merge.h"
42 #include "onak-conf.h"
43 #include "parsekey.h"
44 #include "photoid.h"
45 #include "version.h"
46
47 void find_keys(struct onak_dbctx *dbctx,
48                 char *search, uint64_t keyid, uint8_t *fp, bool ishex,
49                 bool isfp, bool fingerprint, bool skshash, bool exact,
50                 bool verbose)
51 {
52         struct openpgp_publickey *publickey = NULL;
53         int count = 0;
54
55         if (ishex) {
56                 count = dbctx->fetch_key_id(dbctx, keyid, &publickey,
57                                 false);
58         } else if (isfp) {
59                 count = dbctx->fetch_key_fp(dbctx, fp, MAX_FINGERPRINT_LEN,
60                                 &publickey, false);
61         } else {
62                 count = dbctx->fetch_key_text(dbctx, search, &publickey);
63         }
64         if (publickey != NULL) {
65                 key_index(dbctx, publickey, verbose, fingerprint, skshash,
66                         false);
67                 free_publickey(publickey);
68         } else if (count == 0) {
69                 puts("Key not found.");
70         } else {
71                 printf("Found %d keys, but maximum number to return is %d.\n",
72                                 count,
73                                 config.maxkeys);
74                 puts("Try again with a more specific search.");
75         }
76 }
77
78 /**
79  * @brief Context for the keyserver dumping function
80  */
81 struct dump_ctx {
82         /** Keys we've dumped so far to this file */
83         int count;
84         /** Maximum keys to dump per file */
85         int maxcount;
86         /** File descriptor for the current dump file */
87         int fd;
88         /** Number of the current dump file */
89         int filenum;
90         /** Base filename to use for dump files */
91         char *filebase;
92 };
93
94 void dump_func(void *ctx, struct openpgp_publickey *key)
95 {
96         struct openpgp_packet_list *packets = NULL;
97         struct openpgp_packet_list *list_end = NULL;
98         struct dump_ctx *state;
99         char filename[1024];
100
101         state = (struct dump_ctx *) ctx;
102
103         if (state->fd == -1 || state->count++ > state->maxcount) {
104                 if (state->fd != -1) {
105                         close(state->fd);
106                         state->fd = -1;
107                 }
108                 snprintf(filename, 1023, state->filebase, state->filenum);
109                 state->fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0640);
110                 state->filenum++;
111                 state->count = 0;
112         }
113         flatten_publickey(key, &packets, &list_end);
114         write_openpgp_stream(file_putchar, &state->fd, packets);
115         free_packet_list(packets);
116         packets = list_end = NULL;
117
118         return;
119 }
120
121 static uint8_t hex2bin(char c)
122 {
123         if (c >= '0' && c <= '9') {
124                 return (c - '0');
125         } else if (c >= 'a' && c <= 'f') {
126                 return (c - 'a' + 10);
127         } else if (c >= 'A' && c <= 'F') {
128                 return (c - 'A' + 10);
129         }
130
131         return 255;
132 }
133
134 void usage(void) {
135         puts("onak " ONAK_VERSION " - an OpenPGP keyserver.\n");
136         puts("Usage:\n");
137         puts("\tonak [options] <command> <parameters>\n");
138         puts("\tCommands:\n");
139         puts("\tadd      - read armored OpenPGP keys from stdin and add to the"
140                 " keyserver");
141         puts("\tclean    - read armored OpenPGP keys from stdin, run the"
142                 " cleaning\n\t             routines against them and dump to"
143                 " stdout");
144         puts("\tdelete   - delete a given key from the keyserver");
145         puts("\tdump     - dump all the keys from the keyserver to a file or"
146                 " files\n\t           starting keydump*");
147         puts("\tget      - retrieves the key requested from the keyserver");
148         puts("\tgetphoto - retrieves the first photoid on the given key and"
149                 " dumps to\n\t           stdout");
150         puts("\tindex    - search for a key and list it");
151         puts("\tvindex   - search for a key and list it and its signatures");
152 }
153
154 int main(int argc, char *argv[])
155 {
156         struct openpgp_packet_list      *packets = NULL;
157         struct openpgp_packet_list      *list_end = NULL;
158         struct openpgp_publickey        *keys = NULL;
159         char                            *configfile = NULL;
160         int                              rc = EXIT_SUCCESS;
161         int                              result = 0;
162         char                            *search = NULL;
163         char                            *end = NULL;
164         uint64_t                         keyid = 0;
165         uint8_t                          fp[MAX_FINGERPRINT_LEN];
166         int                              i;
167         bool                             ishex = false;
168         bool                             isfp = false;
169         bool                             update = false;
170         bool                             binary = false;
171         bool                             fingerprint = false;
172         bool                             skshash = false;
173         int                              optchar;
174         struct dump_ctx                  dumpstate;
175         struct skshash                   hash;
176         struct onak_dbctx               *dbctx;
177
178         while ((optchar = getopt(argc, argv, "bc:fsuv")) != -1 ) {
179                 switch (optchar) {
180                 case 'b': 
181                         binary = true;
182                         break;
183                 case 'c':
184                         configfile = strdup(optarg);
185                         break;
186                 case 'f': 
187                         fingerprint = true;
188                         break;
189                 case 's': 
190                         skshash = true;
191                         break;
192                 case 'u': 
193                         update = true;
194                         break;
195                 case 'v': 
196                         setlogthreshold(LOGTHING_INFO);
197                         break;
198                 }
199         }
200
201         readconfig(configfile);
202         initlogthing("onak", config.logfile);
203         catchsignals();
204
205         if ((argc - optind) < 1) {
206                 usage();
207         } else if (!strcmp("dump", argv[optind])) {
208                 dbctx = config.dbinit(true);
209                 dumpstate.count = dumpstate.filenum = 0;
210                 dumpstate.maxcount = 100000;
211                 dumpstate.fd = -1;
212                 dumpstate.filebase = "keydump.%d.pgp";
213                 dbctx->iterate_keys(dbctx, dump_func, &dumpstate);
214                 if (dumpstate.fd != -1) {
215                         close(dumpstate.fd);
216                         dumpstate.fd = -1;
217                 }
218                 dbctx->cleanupdb(dbctx);
219         } else if (!strcmp("add", argv[optind])) {
220                 if (binary) {
221                         result = read_openpgp_stream(stdin_getchar, NULL,
222                                  &packets, 0);
223                         logthing(LOGTHING_INFO,
224                                         "read_openpgp_stream: %d", result);
225                 } else {
226                         dearmor_openpgp_stream(stdin_getchar, NULL, &packets);
227                 }
228                 if (packets != NULL) {
229                         result = parse_keys(packets, &keys);
230                         free_packet_list(packets);
231                         packets = NULL;
232                         logthing(LOGTHING_INFO, "Finished reading %d keys.",
233                                         result);
234
235                         result = cleankeys(keys);
236                         logthing(LOGTHING_INFO, "%d keys cleaned.",
237                                         result);
238
239                         dbctx = config.dbinit(false);
240                         logthing(LOGTHING_NOTICE, "Got %d new keys.",
241                                         dbctx->update_keys(dbctx, &keys,
242                                         false));
243                         if (keys != NULL && update) {
244                                 flatten_publickey(keys,
245                                         &packets,
246                                         &list_end);
247                                 if (binary) {
248                                         write_openpgp_stream(stdout_putchar,
249                                                         NULL,
250                                                         packets);
251                                 } else {
252                                         armor_openpgp_stream(stdout_putchar,
253                                                 NULL,
254                                                 packets);
255                                 }
256                                 free_packet_list(packets);
257                                 packets = NULL;
258                         }
259                         dbctx->cleanupdb(dbctx);
260                 } else {
261                         rc = 1;
262                         logthing(LOGTHING_NOTICE, "No keys read.");
263                 }
264
265                 if (keys != NULL) {
266                         free_publickey(keys);
267                         keys = NULL;
268                 } else {
269                         rc = 1;
270                         logthing(LOGTHING_NOTICE, "No changes.");
271                 }
272         } else if (!strcmp("clean", argv[optind])) {
273                 if (binary) {
274                         result = read_openpgp_stream(stdin_getchar, NULL,
275                                  &packets, 0);
276                         logthing(LOGTHING_INFO,
277                                         "read_openpgp_stream: %d", result);
278                 } else {
279                         dearmor_openpgp_stream(stdin_getchar, NULL, &packets);
280                 }
281
282                 if (packets != NULL) {
283                         result = parse_keys(packets, &keys);
284                         free_packet_list(packets);
285                         packets = NULL;
286                         logthing(LOGTHING_INFO, "Finished reading %d keys.",
287                                         result);
288
289                         if (keys != NULL) {
290                                 result = cleankeys(keys);
291                                 logthing(LOGTHING_INFO, "%d keys cleaned.",
292                                                 result);
293
294                                 flatten_publickey(keys,
295                                         &packets,
296                                         &list_end);
297
298                                 if (binary) {
299                                         write_openpgp_stream(stdout_putchar,
300                                                         NULL,
301                                                         packets);
302                                 } else {
303                                         armor_openpgp_stream(stdout_putchar,
304                                                 NULL,
305                                                 packets);
306                                 }
307                                 free_packet_list(packets);
308                                 packets = NULL;
309                         }
310                 } else {
311                         rc = 1;
312                         logthing(LOGTHING_NOTICE, "No keys read.");
313                 }
314                 
315                 if (keys != NULL) {
316                         free_publickey(keys);
317                         keys = NULL;
318                 }
319         } else if ((argc - optind) == 2) {
320                 search = argv[optind+1];
321                 if (search != NULL && strlen(search) == 42 &&
322                                 search[0] == '0' && search[1] == 'x') {
323                         for (i = 0; i < MAX_FINGERPRINT_LEN; i++) {
324                                 fp[i] = (hex2bin(search[2 + i * 2]) << 4) +
325                                                 hex2bin(search[3 + i * 2]);
326                         }
327                         isfp = true;
328                 } else if (search != NULL) {
329                         keyid = strtoul(search, &end, 16);
330                         if (*search != 0 &&
331                                         end != NULL &&
332                                         *end == 0) {
333                                 ishex = true;
334                         }
335                 }
336                 dbctx = config.dbinit(false);
337                 if (!strcmp("index", argv[optind])) {
338                         find_keys(dbctx, search, keyid, fp, ishex, isfp,
339                                         fingerprint, skshash,
340                                         false, false);
341                 } else if (!strcmp("vindex", argv[optind])) {
342                         find_keys(dbctx, search, keyid, fp, ishex, isfp,
343                                         fingerprint, skshash,
344                                         false, true);
345                 } else if (!strcmp("getphoto", argv[optind])) {
346                         if (!ishex) {
347                                 puts("Can't get a key on uid text."
348                                         " You must supply a keyid.");
349                         } else if (dbctx->fetch_key_id(dbctx, keyid, &keys,
350                                         false)) {
351                                 unsigned char *photo = NULL;
352                                 size_t         length = 0;
353
354                                 if (getphoto(keys, 0, &photo,
355                                                 &length) == ONAK_E_OK) {
356                                         fwrite(photo,
357                                                 1,
358                                                 length,
359                                                 stdout);
360                                 }
361                                 free_publickey(keys);
362                                 keys = NULL;
363                         } else {
364                                 puts("Key not found");
365                         }
366                 } else if (!strcmp("delete", argv[optind])) {
367                         dbctx->delete_key(dbctx,
368                                         dbctx->getfullkeyid(dbctx, keyid),
369                                         false);
370                 } else if (!strcmp("get", argv[optind])) {
371                         if (!(ishex || isfp)) {
372                                 puts("Can't get a key on uid text."
373                                         " You must supply a keyid / "
374                                         "fingerprint.");
375                         } else if ((isfp &&
376                                         dbctx->fetch_key_fp(dbctx, fp,
377                                                 MAX_FINGERPRINT_LEN,
378                                                 &keys, false)) ||
379                                         (ishex &&
380                                         dbctx->fetch_key_id(dbctx, keyid,
381                                                 &keys, false))) {
382                                 logthing(LOGTHING_INFO, "Got key.");
383                                 flatten_publickey(keys,
384                                                 &packets,
385                                                 &list_end);
386                                 free_publickey(keys);
387                                 if (binary) {
388                                         write_openpgp_stream(stdout_putchar,
389                                                 NULL,
390                                                 packets);
391                                 } else {
392                                         armor_openpgp_stream(stdout_putchar,
393                                                 NULL,
394                                                 packets);
395                                 }
396                                 free_packet_list(packets);
397                                 packets = NULL;
398                         } else {
399                                 puts("Key not found");
400                         }
401                 } else if (!strcmp("hget", argv[optind])) {
402                         if (!parse_skshash(search, &hash)) {
403                                 puts("Couldn't parse sks hash.");
404                         } else if (dbctx->fetch_key_skshash(dbctx, &hash,
405                                         &keys)) {
406                                 logthing(LOGTHING_INFO, "Got key.");
407                                 flatten_publickey(keys,
408                                                 &packets,
409                                                 &list_end);
410                                 free_publickey(keys);
411                                 if (binary) {
412                                         write_openpgp_stream(stdout_putchar,
413                                                 NULL,
414                                                 packets);
415                                 } else {
416                                         armor_openpgp_stream(stdout_putchar,
417                                                 NULL,
418                                                 packets);
419                                 }
420                                 free_packet_list(packets);
421                                 packets = NULL;
422                         } else {
423                                 puts("Key not found");
424                         }
425                 }
426                 dbctx->cleanupdb(dbctx);
427         } else {
428                 usage();
429         }
430
431         cleanuplogthing();
432         cleanupconfig();
433
434         return rc;
435 }