]> git.sommitrealweird.co.uk Git - onak.git/blob - keydb_dynamic.c
10bec165e6decd21c6820095fd6f21abfd0057fa
[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(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 != NULL) {
159                         return loaded_backend->fetch_key(keyid,publickey,intrans);
160                 }
161         }
162
163         return -1;
164 }
165
166 static int dynamic_store_key(struct openpgp_publickey *publickey, bool intrans,
167                 bool update)
168 {
169         if (loaded_backend == NULL) {
170                 load_backend();
171         }
172         
173         if (loaded_backend != NULL) {
174                 if (loaded_backend->store_key != NULL) {
175                         return loaded_backend->store_key(publickey,intrans,update);
176                 }
177         }
178
179         return -1;
180 }
181
182 static int dynamic_delete_key(uint64_t keyid, bool intrans)
183 {
184         if (loaded_backend == NULL) {
185                 load_backend();
186         }
187         
188         if (loaded_backend != NULL) {
189                 if (loaded_backend->delete_key != NULL) {
190                         return loaded_backend->delete_key(keyid, intrans);
191                 }
192         }
193
194         return -1;
195 }
196
197 static int dynamic_fetch_key_text(const char *search,
198                 struct openpgp_publickey **publickey)
199 {
200         if (loaded_backend == NULL) {
201                 load_backend();
202         }
203         
204         if (loaded_backend != NULL) {
205                 if (loaded_backend->fetch_key_text != NULL) {
206                         return loaded_backend->fetch_key_text(search, publickey);
207                 }
208         }
209
210         return -1;
211 }
212
213 static int dynamic_fetch_key_skshash(const struct skshash *hash,
214                 struct openpgp_publickey **publickey)
215 {
216         if (loaded_backend == NULL) {
217                 load_backend();
218         }
219         
220         if (loaded_backend != NULL) {
221                 if (loaded_backend->fetch_key_skshash != NULL) {
222                         return loaded_backend->fetch_key_skshash(hash,
223                                                                 publickey);
224                 }
225         }
226
227         return -1;
228 }
229
230 static int dynamic_iterate_keys(void (*iterfunc)(void *ctx,
231                 struct openpgp_publickey *key), void *ctx)
232 {
233         if (loaded_backend == NULL) {
234                 load_backend();
235         }
236         
237         if (loaded_backend != NULL) {
238                 if (loaded_backend->iterate_keys != NULL) {
239                         return loaded_backend->iterate_keys(iterfunc, ctx);
240                 }
241         }
242
243         return -1;
244 }
245
246 /**
247  *      keyid2uid - Takes a keyid and returns the primary UID for it.
248  *      @keyid: The keyid to lookup.
249  */
250 static char *dynamic_keyid2uid(uint64_t keyid)
251 {
252         struct openpgp_publickey *publickey = NULL;
253         struct openpgp_signedpacket_list *curuid = NULL;
254         char buf[1024];
255
256         if (loaded_backend == NULL) {
257                 load_backend();
258         }
259         
260         if (loaded_backend != NULL) {
261                 if (loaded_backend->keyid2uid != NULL) {
262                         return loaded_backend->keyid2uid(keyid);
263                 }
264         }
265         
266         buf[0]=0;
267         if (dynamic_fetch_key(keyid, &publickey, false) && publickey != NULL) {
268                 curuid = publickey->uids;
269                 while (curuid != NULL && buf[0] == 0) {
270                         if (curuid->packet->tag == OPENPGP_PACKET_UID) {
271                                 snprintf(buf, 1023, "%.*s",
272                                                 (int) curuid->packet->length,
273                                                 curuid->packet->data);
274                         }
275                         curuid = curuid -> next;
276                 }
277                 free_publickey(publickey);
278         }
279
280         if (buf[0] == 0) {
281                 return NULL;
282         } else {
283                 return strdup(buf);
284         }
285 }
286
287 /**
288  *      getkeysigs - Gets a linked list of the signatures on a key.
289  *      @keyid: The keyid to get the sigs for.
290  *      @revoked: Is the key revoked?
291  *
292  *      This function gets the list of signatures on a key. Used for key 
293  *      indexing and doing stats bits. If revoked is non-NULL then if the key
294  *      is revoked it's set to true.
295  */
296 static struct ll *dynamic_getkeysigs(uint64_t keyid, bool *revoked)
297 {
298         struct ll *sigs = NULL;
299         struct openpgp_signedpacket_list *uids = NULL;
300         struct openpgp_publickey *publickey = NULL;
301         
302         if ( loaded_backend == NULL ) {
303                 load_backend();
304         }
305         
306         if (loaded_backend != NULL) {
307                 if (loaded_backend->getkeysigs != NULL) {
308                         return loaded_backend->getkeysigs(keyid,revoked);
309                 }
310         }
311
312         dynamic_fetch_key(keyid, &publickey, false);
313         
314         if (publickey != NULL) {
315                 for (uids = publickey->uids; uids != NULL; uids = uids->next) {
316                         sigs = keysigs(sigs, uids->sigs);
317                 }
318                 if (revoked != NULL) {
319                         *revoked = publickey->revoked;
320                 }
321                 free_publickey(publickey);
322         }
323
324         return sigs;
325 }
326
327 /**
328  *      cached_getkeysigs - Gets the signatures on a key.
329  *      @keyid: The key we want the signatures for.
330  *      
331  *      This function gets the signatures on a key. It's the same as the
332  *      getkeysigs function above except we use the hash module to cache the
333  *      data so if we need it again it's already loaded.
334  */
335 static struct ll *dynamic_cached_getkeysigs(uint64_t keyid)
336 {
337         struct stats_key *key = NULL;
338         struct stats_key *signedkey = NULL;
339         struct ll        *cursig = NULL;
340         bool              revoked = false;
341
342         if (keyid == 0)  {
343                 return NULL;
344         }
345         
346         if (loaded_backend == NULL) {
347                 load_backend();
348         }
349         
350         if (loaded_backend != NULL) {
351                 if (loaded_backend->cached_getkeysigs != NULL) {
352                         return loaded_backend->cached_getkeysigs(keyid);
353                 }
354         }
355
356         key = createandaddtohash(keyid);
357
358         if (key->gotsigs == false) {
359                 key->sigs = dynamic_getkeysigs(key->keyid, &revoked);
360                 key->revoked = revoked;
361                 for (cursig = key->sigs; cursig != NULL;
362                                 cursig = cursig->next) {
363                         signedkey = (struct stats_key *) cursig->object;
364                         signedkey->signs = lladd(signedkey->signs, key);
365                 }
366                 key->gotsigs = true;
367         }
368
369         return key->sigs;
370 }
371
372 /**
373  *      getfullkeyid - Maps a 32bit key id to a 64bit one.
374  *      @keyid: The 32bit keyid.
375  *
376  *      This function maps a 32bit key id to the full 64bit one. It returns the
377  *      full keyid. If the key isn't found a keyid of 0 is returned.
378  */
379 static uint64_t dynamic_getfullkeyid(uint64_t keyid)
380 {
381         struct openpgp_publickey *publickey = NULL;
382
383         if (loaded_backend == NULL) {
384                 load_backend();
385         }
386         
387         if (loaded_backend != NULL) {
388                 if (loaded_backend->getfullkeyid != NULL) {
389                         return loaded_backend->getfullkeyid(keyid);
390                 }
391         }
392
393         if (keyid < 0x100000000LL) {
394                 dynamic_fetch_key(keyid, &publickey, false);
395                 if (publickey != NULL) {
396                         keyid = get_keyid(publickey);
397                         free_publickey(publickey);
398                         publickey = NULL;
399                 } else {
400                         keyid = 0;
401                 }
402         }
403         
404         return keyid;
405 }
406
407 /**
408  *      update_keys - Takes a list of public keys and updates them in the DB.
409  *      @keys: The keys to update in the DB.
410  *      @sendsync: Should we send a sync mail to our peers.
411  *
412  *      Takes a list of keys and adds them to the database, merging them with
413  *      the key in the database if it's already present there. The key list is
414  *      update to contain the minimum set of updates required to get from what
415  *      we had before to what we have now (ie the set of data that was added to
416  *      the DB). Returns the number of entirely new keys added.
417  */
418 static int dynamic_update_keys(struct openpgp_publickey **keys, bool sendsync)
419 {
420         struct openpgp_publickey *curkey = NULL;
421         struct openpgp_publickey *oldkey = NULL;
422         struct openpgp_publickey *prev = NULL;
423         int newkeys = 0;
424         bool intrans;
425         
426         if (loaded_backend == NULL) {
427                 load_backend();
428         }
429         
430         if (loaded_backend != NULL) {
431                 if (loaded_backend->update_keys != NULL) {
432                         return loaded_backend->update_keys(keys, sendsync);
433                 }
434         }
435
436         for (curkey = *keys; curkey != NULL; curkey = curkey->next) {
437                 intrans = dynamic_starttrans();
438                 logthing(LOGTHING_INFO,
439                         "Fetching key 0x%" PRIX64 ", result: %d",
440                         get_keyid(curkey),
441                         dynamic_fetch_key(get_keyid(curkey), &oldkey, intrans));
442
443                 /*
444                  * If we already have the key stored in the DB then merge it
445                  * with the new one that's been supplied. Otherwise the key
446                  * we've just got is the one that goes in the DB and also the
447                  * one that we send out.
448                  */
449                 if (oldkey != NULL) {
450                         merge_keys(oldkey, curkey);
451                         if (curkey->sigs == NULL &&
452                                         curkey->uids == NULL &&
453                                         curkey->subkeys == NULL) {
454                                 if (prev == NULL) {
455                                         *keys = curkey->next;
456                                 } else {
457                                         prev->next = curkey->next;
458                                         curkey->next = NULL;
459                                         free_publickey(curkey);
460                                         curkey = prev;
461                                 }
462                         } else {
463                                 prev = curkey;
464                                 logthing(LOGTHING_INFO,
465                                         "Merged key; storing updated key.");
466                                 dynamic_store_key(oldkey, intrans, true);
467                         }
468                         free_publickey(oldkey);
469                         oldkey = NULL;
470                 
471                 } else {
472                         logthing(LOGTHING_INFO,
473                                 "Storing completely new key.");
474                         dynamic_store_key(curkey, intrans, false);
475                         newkeys++;
476                 }
477                 dynamic_endtrans();
478                 intrans = false;
479         }
480
481         if (sendsync && keys != NULL) {
482                 sendkeysync(*keys);
483         }
484
485         return newkeys;
486 }
487
488 static void dynamic_initdb(bool readonly)
489 {
490         if (loaded_backend == NULL) {
491                 load_backend();
492         }
493
494         if (loaded_backend != NULL) {
495                 if (loaded_backend->initdb != NULL) {
496                         loaded_backend->initdb(readonly);
497                 }
498         }
499 }
500
501 static void dynamic_cleanupdb(void)
502 {
503         if (loaded_backend != NULL) {
504                 if (loaded_backend->cleanupdb != NULL) {
505                         loaded_backend->cleanupdb();
506                 }
507         }
508
509         close_backend();
510 }
511
512 struct dbfuncs keydb_dynamic_funcs = {
513         .initdb                 = dynamic_initdb,
514         .cleanupdb              = dynamic_cleanupdb,
515         .starttrans             = dynamic_starttrans,
516         .endtrans               = dynamic_endtrans,
517         .fetch_key              = dynamic_fetch_key,
518         .fetch_key_text         = dynamic_fetch_key_text,
519         .fetch_key_skshash      = dynamic_fetch_key_skshash,
520         .store_key              = dynamic_store_key,
521         .update_keys            = dynamic_update_keys,
522         .delete_key             = dynamic_delete_key,
523         .getkeysigs             = dynamic_getkeysigs,
524         .cached_getkeysigs      = dynamic_cached_getkeysigs,
525         .keyid2uid              = dynamic_keyid2uid,
526         .getfullkeyid           = dynamic_getfullkeyid,
527         .iterate_keys           = dynamic_iterate_keys,
528 };