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