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