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