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