]> the.earth.li Git - onak.git/blob - keydb_dynamic.c
Skip signature hash verification for X509 signatures
[onak.git] / keydb_dynamic.c
1 /*
2  * keydb_dynamic.c - backend that can load the other backends
3  *
4  * Copyright 2005 Brett Parker <iDunno@sommitrealweird.co.uk>
5  *
6  * This program is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the Free
8  * Software Foundation; version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * this program; if not, write to the Free Software Foundation, Inc., 51
17  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19
20 #include <dlfcn.h>
21 #include <stdio.h>
22 #include <string.h>
23
24 #include "decodekey.h"
25 #include "hash.h"
26 #include "keydb.h"
27 #include "keyid.h"
28 #include "keystructs.h"
29 #include "log.h"
30 #include "mem.h"
31 #include "merge.h"
32 #include "onak-conf.h"
33 #include "openpgp.h"
34 #include "parsekey.h"
35 #include "sendsync.h"
36
37 static struct dbfuncs *loaded_backend = NULL;
38 static void *backend_handle;
39
40 static bool close_backend(void)
41 {
42         loaded_backend = NULL;
43         dlclose(backend_handle);
44         backend_handle = NULL;
45
46         return true;
47 }
48
49 static bool load_backend(void)
50 {
51         char *soname = NULL;
52         char *funcsname = NULL;
53
54         if (loaded_backend != NULL) {
55                 close_backend();
56                 loaded_backend = NULL;
57         }
58
59         if (config.use_keyd) {
60                 free(config.db_backend);
61                 config.db_backend = strdup("keyd");
62         }
63
64         if (!config.db_backend) {
65                 logthing(LOGTHING_CRITICAL, "No database backend defined.");
66                 exit(EXIT_FAILURE);
67         }
68
69         if (config.backends_dir == NULL) {
70                 soname = malloc(strlen(config.db_backend)
71                         + strlen("./libkeydb_")
72                         + strlen(".so")
73                         + 1);
74
75                 sprintf(soname, "./libkeydb_%s.so", config.db_backend);
76         } else {
77                 soname = malloc(strlen(config.db_backend)
78                         + strlen("/libkeydb_")
79                         + strlen(".so")
80                         + strlen(config.backends_dir)
81                         + 1);
82
83                 sprintf(soname, "%s/libkeydb_%s.so", config.backends_dir,
84                         config.db_backend);
85         }
86                 
87         logthing(LOGTHING_INFO, "Loading dynamic backend: %s", soname);
88
89         backend_handle = dlopen(soname, RTLD_LAZY);
90         if (backend_handle == NULL) {
91                 logthing(LOGTHING_CRITICAL,
92                                 "Failed to open handle to library '%s': %s",
93                                 soname, dlerror());
94                 free(soname);
95                 soname = NULL;
96                 exit(EXIT_FAILURE);
97         }
98
99         funcsname = malloc(strlen(config.db_backend)
100                         + strlen("keydb_")
101                         + strlen("_funcs")
102                         + 1);
103         sprintf(funcsname, "keydb_%s_funcs", config.db_backend);
104
105         loaded_backend = dlsym(backend_handle, funcsname);
106         free(funcsname);
107
108         if (loaded_backend == NULL) {
109                 logthing(LOGTHING_CRITICAL,
110                                 "Failed to find dbfuncs structure in library "
111                                 "'%s' : %s", soname, dlerror());
112                 free(soname);
113                 soname = NULL;
114                 exit(EXIT_FAILURE);
115         }
116         free(soname);
117         soname = NULL;
118
119         return true;
120 }
121
122 static bool dynamic_starttrans()
123 {
124         if (loaded_backend == NULL) {
125                 load_backend();
126         }
127         
128         if (loaded_backend != NULL) {
129                 if (loaded_backend->starttrans != NULL) {
130                         return loaded_backend->starttrans();
131                 }
132         }
133
134         return false;
135 }
136
137 static void dynamic_endtrans()
138 {
139         if (loaded_backend == NULL) {
140                 load_backend();
141         }
142         
143         if (loaded_backend != NULL) {
144                 if (loaded_backend->endtrans != NULL) {
145                         loaded_backend->endtrans();
146                 }
147         }
148 }
149
150 static int dynamic_fetch_key_id(uint64_t keyid,
151                 struct openpgp_publickey **publickey, bool intrans)
152 {
153         if (loaded_backend == NULL) {
154                 load_backend();
155         }
156
157         if (loaded_backend != NULL) {
158                 if (loaded_backend->fetch_key_id != NULL) {
159                         return loaded_backend->fetch_key_id(keyid,
160                                 publickey, intrans);
161                 }
162         }
163
164         return -1;
165 }
166
167 static int dynamic_fetch_key_fp(uint8_t *fp, size_t fpsize,
168                 struct openpgp_publickey **publickey, bool intrans)
169 {
170         if (loaded_backend == NULL) {
171                 load_backend();
172         }
173
174         if (loaded_backend != NULL) {
175                 if (loaded_backend->fetch_key_id != NULL) {
176                         return loaded_backend->fetch_key_fp(fp, fpsize,
177                                 publickey, intrans);
178                 }
179         }
180
181         return -1;
182 }
183
184
185
186 static int dynamic_store_key(struct openpgp_publickey *publickey, bool intrans,
187                 bool update)
188 {
189         if (loaded_backend == NULL) {
190                 load_backend();
191         }
192         
193         if (loaded_backend != NULL) {
194                 if (loaded_backend->store_key != NULL) {
195                         return loaded_backend->store_key(publickey,intrans,update);
196                 }
197         }
198
199         return -1;
200 }
201
202 static int dynamic_delete_key(uint64_t keyid, bool intrans)
203 {
204         if (loaded_backend == NULL) {
205                 load_backend();
206         }
207         
208         if (loaded_backend != NULL) {
209                 if (loaded_backend->delete_key != NULL) {
210                         return loaded_backend->delete_key(keyid, intrans);
211                 }
212         }
213
214         return -1;
215 }
216
217 static int dynamic_fetch_key_text(const char *search,
218                 struct openpgp_publickey **publickey)
219 {
220         if (loaded_backend == NULL) {
221                 load_backend();
222         }
223         
224         if (loaded_backend != NULL) {
225                 if (loaded_backend->fetch_key_text != NULL) {
226                         return loaded_backend->fetch_key_text(search, publickey);
227                 }
228         }
229
230         return -1;
231 }
232
233 static int dynamic_fetch_key_skshash(const struct skshash *hash,
234                 struct openpgp_publickey **publickey)
235 {
236         if (loaded_backend == NULL) {
237                 load_backend();
238         }
239         
240         if (loaded_backend != NULL) {
241                 if (loaded_backend->fetch_key_skshash != NULL) {
242                         return loaded_backend->fetch_key_skshash(hash,
243                                                                 publickey);
244                 }
245         }
246
247         return -1;
248 }
249
250 static int dynamic_iterate_keys(void (*iterfunc)(void *ctx,
251                 struct openpgp_publickey *key), void *ctx)
252 {
253         if (loaded_backend == NULL) {
254                 load_backend();
255         }
256         
257         if (loaded_backend != NULL) {
258                 if (loaded_backend->iterate_keys != NULL) {
259                         return loaded_backend->iterate_keys(iterfunc, ctx);
260                 }
261         }
262
263         return -1;
264 }
265
266 /**
267  *      keyid2uid - Takes a keyid and returns the primary UID for it.
268  *      @keyid: The keyid to lookup.
269  */
270 static char *dynamic_keyid2uid(uint64_t keyid)
271 {
272         struct openpgp_publickey *publickey = NULL;
273         struct openpgp_signedpacket_list *curuid = NULL;
274         char buf[1024];
275
276         if (loaded_backend == NULL) {
277                 load_backend();
278         }
279         
280         if (loaded_backend != NULL) {
281                 if (loaded_backend->keyid2uid != NULL) {
282                         return loaded_backend->keyid2uid(keyid);
283                 }
284         }
285         
286         buf[0]=0;
287         if (dynamic_fetch_key_id(keyid, &publickey, false) &&
288                         publickey != NULL) {
289                 curuid = publickey->uids;
290                 while (curuid != NULL && buf[0] == 0) {
291                         if (curuid->packet->tag == OPENPGP_PACKET_UID) {
292                                 snprintf(buf, 1023, "%.*s",
293                                                 (int) curuid->packet->length,
294                                                 curuid->packet->data);
295                         }
296                         curuid = curuid -> next;
297                 }
298                 free_publickey(publickey);
299         }
300
301         if (buf[0] == 0) {
302                 return NULL;
303         } else {
304                 return strdup(buf);
305         }
306 }
307
308 /**
309  *      getkeysigs - Gets a linked list of the signatures on a key.
310  *      @keyid: The keyid to get the sigs for.
311  *      @revoked: Is the key revoked?
312  *
313  *      This function gets the list of signatures on a key. Used for key 
314  *      indexing and doing stats bits. If revoked is non-NULL then if the key
315  *      is revoked it's set to true.
316  */
317 static struct ll *dynamic_getkeysigs(uint64_t keyid, bool *revoked)
318 {
319         struct ll *sigs = NULL;
320         struct openpgp_signedpacket_list *uids = NULL;
321         struct openpgp_publickey *publickey = NULL;
322         
323         if ( loaded_backend == NULL ) {
324                 load_backend();
325         }
326         
327         if (loaded_backend != NULL) {
328                 if (loaded_backend->getkeysigs != NULL) {
329                         return loaded_backend->getkeysigs(keyid,revoked);
330                 }
331         }
332
333         dynamic_fetch_key_id(keyid, &publickey, false);
334         
335         if (publickey != NULL) {
336                 for (uids = publickey->uids; uids != NULL; uids = uids->next) {
337                         sigs = keysigs(sigs, uids->sigs);
338                 }
339                 if (revoked != NULL) {
340                         *revoked = publickey->revoked;
341                 }
342                 free_publickey(publickey);
343         }
344
345         return sigs;
346 }
347
348 /**
349  *      cached_getkeysigs - Gets the signatures on a key.
350  *      @keyid: The key we want the signatures for.
351  *      
352  *      This function gets the signatures on a key. It's the same as the
353  *      getkeysigs function above except we use the hash module to cache the
354  *      data so if we need it again it's already loaded.
355  */
356 static struct ll *dynamic_cached_getkeysigs(uint64_t keyid)
357 {
358         struct stats_key *key = NULL;
359         struct stats_key *signedkey = NULL;
360         struct ll        *cursig = NULL;
361         bool              revoked = false;
362
363         if (keyid == 0)  {
364                 return NULL;
365         }
366         
367         if (loaded_backend == NULL) {
368                 load_backend();
369         }
370         
371         if (loaded_backend != NULL) {
372                 if (loaded_backend->cached_getkeysigs != NULL) {
373                         return loaded_backend->cached_getkeysigs(keyid);
374                 }
375         }
376
377         key = createandaddtohash(keyid);
378
379         if (key->gotsigs == false) {
380                 key->sigs = dynamic_getkeysigs(key->keyid, &revoked);
381                 key->revoked = revoked;
382                 for (cursig = key->sigs; cursig != NULL;
383                                 cursig = cursig->next) {
384                         signedkey = (struct stats_key *) cursig->object;
385                         signedkey->signs = lladd(signedkey->signs, key);
386                 }
387                 key->gotsigs = true;
388         }
389
390         return key->sigs;
391 }
392
393 /**
394  *      getfullkeyid - Maps a 32bit key id to a 64bit one.
395  *      @keyid: The 32bit keyid.
396  *
397  *      This function maps a 32bit key id to the full 64bit one. It returns the
398  *      full keyid. If the key isn't found a keyid of 0 is returned.
399  */
400 static uint64_t dynamic_getfullkeyid(uint64_t keyid)
401 {
402         struct openpgp_publickey *publickey = NULL;
403
404         if (loaded_backend == NULL) {
405                 load_backend();
406         }
407         
408         if (loaded_backend != NULL) {
409                 if (loaded_backend->getfullkeyid != NULL) {
410                         return loaded_backend->getfullkeyid(keyid);
411                 }
412         }
413
414         if (keyid < 0x100000000LL) {
415                 dynamic_fetch_key_id(keyid, &publickey, false);
416                 if (publickey != NULL) {
417                         get_keyid(publickey, &keyid);
418                         free_publickey(publickey);
419                         publickey = NULL;
420                 } else {
421                         keyid = 0;
422                 }
423         }
424         
425         return keyid;
426 }
427
428 /**
429  *      update_keys - Takes a list of public keys and updates them in the DB.
430  *      @keys: The keys to update in the DB.
431  *      @sendsync: Should we send a sync mail to our peers.
432  *
433  *      Takes a list of keys and adds them to the database, merging them with
434  *      the key in the database if it's already present there. The key list is
435  *      update to contain the minimum set of updates required to get from what
436  *      we had before to what we have now (ie the set of data that was added to
437  *      the DB). Returns the number of entirely new keys added.
438  */
439 static int dynamic_update_keys(struct openpgp_publickey **keys, bool sendsync)
440 {
441         struct openpgp_publickey *curkey = NULL;
442         struct openpgp_publickey *oldkey = NULL;
443         struct openpgp_publickey *prev = NULL;
444         int newkeys = 0;
445         bool intrans;
446         uint64_t keyid;
447         
448         if (loaded_backend == NULL) {
449                 load_backend();
450         }
451         
452         if (loaded_backend != NULL) {
453                 if (loaded_backend->update_keys != NULL) {
454                         return loaded_backend->update_keys(keys, sendsync);
455                 }
456         }
457
458         for (curkey = *keys; curkey != NULL; curkey = curkey->next) {
459                 intrans = dynamic_starttrans();
460                 get_keyid(curkey, &keyid);
461                 logthing(LOGTHING_INFO,
462                         "Fetching key 0x%" PRIX64 ", result: %d",
463                         keyid,
464                         dynamic_fetch_key_id(keyid, &oldkey, intrans));
465
466                 /*
467                  * If we already have the key stored in the DB then merge it
468                  * with the new one that's been supplied. Otherwise the key
469                  * we've just got is the one that goes in the DB and also the
470                  * one that we send out.
471                  */
472                 if (oldkey != NULL) {
473                         merge_keys(oldkey, curkey);
474                         if (curkey->sigs == NULL &&
475                                         curkey->uids == NULL &&
476                                         curkey->subkeys == NULL) {
477                                 if (prev == NULL) {
478                                         *keys = curkey->next;
479                                 } else {
480                                         prev->next = curkey->next;
481                                         curkey->next = NULL;
482                                         free_publickey(curkey);
483                                         curkey = prev;
484                                 }
485                         } else {
486                                 prev = curkey;
487                                 logthing(LOGTHING_INFO,
488                                         "Merged key; storing updated key.");
489                                 dynamic_store_key(oldkey, intrans, true);
490                         }
491                         free_publickey(oldkey);
492                         oldkey = NULL;
493                 
494                 } else {
495                         logthing(LOGTHING_INFO,
496                                 "Storing completely new key.");
497                         dynamic_store_key(curkey, intrans, false);
498                         newkeys++;
499                 }
500                 dynamic_endtrans();
501                 intrans = false;
502         }
503
504         if (sendsync && keys != NULL) {
505                 sendkeysync(*keys);
506         }
507
508         return newkeys;
509 }
510
511 static void dynamic_initdb(bool readonly)
512 {
513         if (loaded_backend == NULL) {
514                 load_backend();
515         }
516
517         if (loaded_backend != NULL) {
518                 if (loaded_backend->initdb != NULL) {
519                         loaded_backend->initdb(readonly);
520                 }
521         }
522 }
523
524 static void dynamic_cleanupdb(void)
525 {
526         if (loaded_backend != NULL) {
527                 if (loaded_backend->cleanupdb != NULL) {
528                         loaded_backend->cleanupdb();
529                 }
530         }
531
532         close_backend();
533 }
534
535 struct dbfuncs keydb_dynamic_funcs = {
536         .initdb                 = dynamic_initdb,
537         .cleanupdb              = dynamic_cleanupdb,
538         .starttrans             = dynamic_starttrans,
539         .endtrans               = dynamic_endtrans,
540         .fetch_key_id           = dynamic_fetch_key_id,
541         .fetch_key_fp           = dynamic_fetch_key_fp,
542         .fetch_key_text         = dynamic_fetch_key_text,
543         .fetch_key_skshash      = dynamic_fetch_key_skshash,
544         .store_key              = dynamic_store_key,
545         .update_keys            = dynamic_update_keys,
546         .delete_key             = dynamic_delete_key,
547         .getkeysigs             = dynamic_getkeysigs,
548         .cached_getkeysigs      = dynamic_cached_getkeysigs,
549         .keyid2uid              = dynamic_keyid2uid,
550         .getfullkeyid           = dynamic_getfullkeyid,
551         .iterate_keys           = dynamic_iterate_keys,
552 };