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