]> git.sommitrealweird.co.uk Git - onak.git/blob - keydb_db4.c
80397aacaadaa7465c1c4a9b682aaf598a071c78
[onak.git] / keydb_db4.c
1 /*
2  * keydb_db4.c - Routines to store and fetch keys in a DB4 database.
3  *
4  * Jonathan McDowell <noodles@earth.li>
5  *
6  * Copyright 2002-2004 Project Purple
7  */
8
9 #include <sys/types.h>
10 #include <sys/uio.h>
11 #include <ctype.h>
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <unistd.h>
18
19 #include <db.h>
20
21 #include "charfuncs.h"
22 #include "keyarray.h"
23 #include "keydb.h"
24 #include "keyid.h"
25 #include "decodekey.h"
26 #include "keystructs.h"
27 #include "mem.h"
28 #include "log.h"
29 #include "onak-conf.h"
30 #include "parsekey.h"
31 #include "wordlist.h"
32
33 /**
34  *      dbenv - our database environment.
35  */
36 static DB_ENV *dbenv = NULL;
37
38 /**
39  *      numdb - The number of database files we have.
40  */
41 static int numdbs = 16;
42
43 /**
44  *      dbconn - our connections to the key database files.
45  */
46 static DB **dbconns = NULL;
47
48 /**
49  *      worddb - our connection to the word database.
50  */
51 static DB *worddb = NULL;
52
53 /**
54  *      id32db - our connection to the 32bit ID database.
55  */
56 static DB *id32db = NULL;
57
58 /**
59  *      txn - our current transaction id.
60  */
61 static DB_TXN *txn = NULL;
62
63 DB *keydb(uint64_t keyid)
64 {
65         uint64_t keytrun;
66
67         keytrun = keyid >> 8;
68
69         return(dbconns[keytrun % numdbs]);
70 }
71
72 /**
73  *      initdb - Initialize the key database.
74  *
75  *      This function should be called before any of the other functions in
76  *      this file are called in order to allow the DB to be initialized ready
77  *      for access.
78  */
79 void initdb(bool readonly)
80 {
81         char       buf[1024];
82         FILE      *numdb = NULL;
83         int        ret = 0;
84         int        i = 0;
85         u_int32_t  flags = 0;
86
87         snprintf(buf, sizeof(buf) - 1, "%s/num_keydb", config.db_dir);
88         numdb = fopen(buf, "r");
89         if (numdb != NULL) {
90                 if (fgets(buf, sizeof(buf), numdb) != NULL) {
91                         numdbs = atoi(buf);
92                 }
93                 fclose(numdb);
94         } else if (!readonly) {
95                 logthing(LOGTHING_ERROR, "Couldn't open num_keydb: %s",
96                                 strerror(errno));
97                 numdb = fopen(buf, "w");
98                 if (numdb != NULL) {
99                         fprintf(numdb, "%d", numdbs);
100                         fclose(numdb);
101                 } else {
102                         logthing(LOGTHING_ERROR,
103                                 "Couldn't write num_keydb: %s",
104                                 strerror(errno));
105                 }
106         }
107
108         dbconns = malloc(sizeof (DB *) * numdbs);
109         if (dbconns == NULL) {
110                 logthing(LOGTHING_CRITICAL,
111                                 "Couldn't allocate memory for dbconns");
112                 ret = 1;
113         }
114
115         if (ret == 0) {
116                 ret = db_env_create(&dbenv, 0);
117                 if (ret != 0) {
118                         logthing(LOGTHING_CRITICAL,
119                                 "db_env_create: %s", db_strerror(ret));
120                 }
121         }
122
123         /*
124          * Enable deadlock detection so that we don't block indefinitely on
125          * anything. What we really want is simple 2 state locks, but I'm not
126          * sure how to make the standard DB functions do that yet.
127          */
128         if (ret == 0) {
129                 ret = dbenv->set_lk_detect(dbenv, DB_LOCK_DEFAULT);
130                 if (ret != 0) {
131                         logthing(LOGTHING_CRITICAL,
132                                 "db_env_create: %s", db_strerror(ret));
133                 }
134         }
135
136         if (ret == 0) {
137                 ret = dbenv->open(dbenv, config.db_dir,
138                                 DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_LOCK |
139                                 DB_INIT_TXN |
140                                 DB_CREATE,
141                                 0);
142                 if (ret != 0) {
143                         logthing(LOGTHING_CRITICAL,
144                                         "Error opening db environment: %s (%s)",
145                                         config.db_dir,
146                                         db_strerror(ret));
147                         dbenv->close(dbenv, 0);
148                         dbenv = NULL;
149                 }
150         }
151
152         if (ret == 0) {
153                 starttrans();
154
155                 for (i = 0; !ret && i < numdbs; i++) {
156                         ret = db_create(&dbconns[i], dbenv, 0);
157                         if (ret != 0) {
158                                 logthing(LOGTHING_CRITICAL,
159                                         "db_create: %s", db_strerror(ret));
160                         }
161
162                         if (ret == 0) {
163                                 snprintf(buf, 1023, "keydb.%d.db", i);
164                                 flags = DB_CREATE;
165                                 if (readonly) {
166                                         flags = DB_RDONLY;
167                                 }
168                                 ret = dbconns[i]->open(dbconns[i],
169                                                 txn,
170                                                 buf,
171                                                 "keydb",
172                                                 DB_HASH,
173                                                 flags,
174                                                 0664);
175                                 if (ret != 0) {
176                                         logthing(LOGTHING_CRITICAL,
177                                                 "Error opening key database:"
178                                                 " %s (%s)",
179                                                 buf,
180                                                 db_strerror(ret));
181                                 }
182                         }
183                 }
184
185         }
186
187         if (ret == 0) {
188                 ret = db_create(&worddb, dbenv, 0);
189                 if (ret != 0) {
190                         logthing(LOGTHING_CRITICAL, "db_create: %s",
191                                         db_strerror(ret));
192                 }
193         }
194
195         if (ret == 0) {
196                 ret = worddb->set_flags(worddb, DB_DUP);
197         }
198
199         if (ret == 0) {
200                 ret = worddb->open(worddb, txn, "worddb", "worddb", DB_BTREE,
201                                 flags,
202                                 0664);
203                 if (ret != 0) {
204                         logthing(LOGTHING_CRITICAL,
205                                         "Error opening word database: %s (%s)",
206                                         "worddb",
207                                         db_strerror(ret));
208                 }
209         }
210
211         if (ret == 0) {
212                 ret = db_create(&id32db, dbenv, 0);
213                 if (ret != 0) {
214                         logthing(LOGTHING_CRITICAL, "db_create: %s",
215                                         db_strerror(ret));
216                 }
217         }
218
219         if (ret == 0) {
220                 ret = id32db->set_flags(id32db, DB_DUP);
221         }
222
223         if (ret == 0) {
224                 ret = id32db->open(id32db, txn, "id32db", "id32db", DB_HASH,
225                                 flags,
226                                 0664);
227                 if (ret != 0) {
228                         logthing(LOGTHING_CRITICAL,
229                                         "Error opening id32 database: %s (%s)",
230                                         "id32db",
231                                         db_strerror(ret));
232                 }
233         }
234
235         if (txn != NULL) {
236                 endtrans();
237         }
238
239         if (ret != 0) {
240                 cleanupdb();
241                 logthing(LOGTHING_CRITICAL,
242                                 "Error opening database; exiting");
243                 exit(EXIT_FAILURE);
244         }
245         
246         return;
247 }
248
249 /**
250  *      cleanupdb - De-initialize the key database.
251  *
252  *      This function should be called upon program exit to allow the DB to
253  *      cleanup after itself.
254  */
255 void cleanupdb(void)
256 {
257         int i = 0;
258
259         if (dbenv != NULL) {
260                 dbenv->txn_checkpoint(dbenv, 0, 0, 0);
261                 if (id32db != NULL) {
262                         id32db->close(id32db, 0);
263                         id32db = NULL;
264                 }
265                 if (worddb != NULL) {
266                         worddb->close(worddb, 0);
267                         worddb = NULL;
268                 }
269                 for (i = 0; i < numdbs; i++) {
270                         if (dbconns[i] != NULL) {
271                                 dbconns[i]->close(dbconns[i], 0);
272                                 dbconns[i] = NULL;
273                         }
274                 }
275                 free(dbconns);
276                 dbconns = NULL;
277                 dbenv->close(dbenv, 0);
278                 dbenv = NULL;
279         }
280 }
281
282 /**
283  *      starttrans - Start a transaction.
284  *
285  *      Start a transaction. Intended to be used if we're about to perform many
286  *      operations on the database to help speed it all up, or if we want
287  *      something to only succeed if all relevant operations are successful.
288  */
289 bool starttrans(void)
290 {
291         int ret;
292
293         log_assert(dbenv != NULL);
294         log_assert(txn == NULL);
295
296         ret = dbenv->txn_begin(dbenv,
297                 NULL, /* No parent transaction */
298                 &txn,
299                 0);
300         if (ret != 0) {
301                 logthing(LOGTHING_CRITICAL,
302                                 "Error starting transaction: %s",
303                                 db_strerror(ret));
304                 exit(1);
305         }
306
307         return true;
308 }
309
310 /**
311  *      endtrans - End a transaction.
312  *
313  *      Ends a transaction.
314  */
315 void endtrans(void)
316 {
317         int ret;
318
319         log_assert(dbenv != NULL);
320         log_assert(txn != NULL);
321
322         ret = txn->commit(txn,
323                 0);
324         if (ret != 0) {
325                 logthing(LOGTHING_CRITICAL,
326                                 "Error ending transaction: %s",
327                                 db_strerror(ret));
328                 exit(1);
329         }
330         txn = NULL;
331
332         return;
333 }
334
335 /**
336  *      fetch_key - Given a keyid fetch the key from storage.
337  *      @keyid: The keyid to fetch.
338  *      @publickey: A pointer to a structure to return the key in.
339  *      @intrans: If we're already in a transaction.
340  *
341  *      We use the hex representation of the keyid as the filename to fetch the
342  *      key from. The key is stored in the file as a binary OpenPGP stream of
343  *      packets, so we can just use read_openpgp_stream() to read the packets
344  *      in and then parse_keys() to parse the packets into a publickey
345  *      structure.
346  */
347 int fetch_key(uint64_t keyid, struct openpgp_publickey **publickey,
348                 bool intrans)
349 {
350         struct openpgp_packet_list *packets = NULL;
351         DBT key, data;
352         int ret = 0;
353         int numkeys = 0;
354         struct buffer_ctx fetchbuf;
355
356         if (keyid < 0x100000000LL) {
357                 keyid = getfullkeyid(keyid);
358         }
359
360         memset(&key, 0, sizeof(key));
361         memset(&data, 0, sizeof(data));
362
363         data.size = 0;
364         data.data = NULL;
365
366         key.size = sizeof(keyid);
367         key.data = &keyid;
368
369         if (!intrans) {
370                 starttrans();
371         }
372
373         ret = keydb(keyid)->get(keydb(keyid),
374                         txn,
375                         &key,
376                         &data,
377                         0); /* flags*/
378         
379         if (ret == 0) {
380                 fetchbuf.buffer = data.data;
381                 fetchbuf.offset = 0;
382                 fetchbuf.size = data.size;
383                 read_openpgp_stream(buffer_fetchchar, &fetchbuf,
384                                 &packets, 0);
385                 parse_keys(packets, publickey);
386                 free_packet_list(packets);
387                 packets = NULL;
388                 numkeys++;
389         } else if (ret != DB_NOTFOUND) {
390                 logthing(LOGTHING_ERROR,
391                                 "Problem retrieving key: %s",
392                                 db_strerror(ret));
393         }
394
395         if (!intrans) {
396                 endtrans();
397         }
398
399         return (numkeys);
400 }
401
402 int worddb_cmp(const void *d1, const void *d2)
403 {
404         return memcmp(d1, d2, 12);
405 }
406
407 /**
408  *      fetch_key_text - Trys to find the keys that contain the supplied text.
409  *      @search: The text to search for.
410  *      @publickey: A pointer to a structure to return the key in.
411  *
412  *      This function searches for the supplied text and returns the keys that
413  *      contain it.
414  */
415 int fetch_key_text(const char *search, struct openpgp_publickey **publickey)
416 {
417         DBC *cursor = NULL;
418         DBT key, data;
419         int ret;
420         uint64_t keyid;
421         int i;
422         int numkeys;
423         char *searchtext = NULL;
424         struct ll *wordlist = NULL;
425         struct ll *curword = NULL;
426         struct keyarray keylist = { NULL, 0, 0 };
427         struct keyarray newkeylist = { NULL, 0, 0 };
428
429         numkeys = 0;
430         searchtext = strdup(search);
431         wordlist = makewordlist(wordlist, searchtext);
432
433         for (curword = wordlist; curword != NULL; curword = curword->next) {
434                 starttrans();
435
436                 ret = worddb->cursor(worddb,
437                                 txn,
438                                 &cursor,
439                                 0);   /* flags */
440
441                 memset(&key, 0, sizeof(key));
442                 memset(&data, 0, sizeof(data));
443                 key.data = curword->object;
444                 key.size = strlen(curword->object);
445                 data.flags = DB_DBT_MALLOC;
446                 ret = cursor->c_get(cursor,
447                                 &key,
448                                 &data,
449                                 DB_SET);
450                 while (ret == 0 && strncmp(key.data, curword->object,
451                                         key.size) == 0 &&
452                                 ((char *) curword->object)[key.size] == 0) {
453                         keyid = 0;
454                         for (i = 4; i < 12; i++) {
455                                 keyid <<= 8;
456                                 keyid += ((unsigned char *)
457                                                 data.data)[i];
458                         }
459
460                         if (keylist.count == 0 ||
461                                         array_find(&keylist, keyid)) {
462                                 array_add(&newkeylist, keyid);
463                         }
464
465                         free(data.data);
466                         data.data = NULL;
467
468                         ret = cursor->c_get(cursor,
469                                         &key,
470                                         &data,
471                                         DB_NEXT);
472                 }
473                 array_free(&keylist);
474                 keylist = newkeylist;
475                 newkeylist.keys = NULL;
476                 newkeylist.count = newkeylist.size = 0;
477                 if (data.data != NULL) {
478                         free(data.data);
479                         data.data = NULL;
480                 }
481                 ret = cursor->c_close(cursor);
482                 cursor = NULL;
483                 endtrans();
484         }
485         llfree(wordlist, NULL);
486         wordlist = NULL;
487         
488         starttrans();
489         for (i = 0; i < keylist.count; i++) {
490                 numkeys += fetch_key(keylist.keys[i],
491                         publickey,
492                         true);
493         }
494         array_free(&keylist);
495         free(searchtext);
496         searchtext = NULL;
497
498         endtrans();
499         
500         return (numkeys);
501 }
502
503 /**
504  *      store_key - Takes a key and stores it.
505  *      @publickey: A pointer to the public key to store.
506  *      @intrans: If we're already in a transaction.
507  *      @update: If true the key exists and should be updated.
508  *
509  *      Again we just use the hex representation of the keyid as the filename
510  *      to store the key to. We flatten the public key to a list of OpenPGP
511  *      packets and then use write_openpgp_stream() to write the stream out to
512  *      the file. If update is true then we delete the old key first, otherwise
513  *      we trust that it doesn't exist.
514  */
515 int store_key(struct openpgp_publickey *publickey, bool intrans, bool update)
516 {
517         struct     openpgp_packet_list *packets = NULL;
518         struct     openpgp_packet_list *list_end = NULL;
519         struct     openpgp_publickey *next = NULL;
520         int        ret = 0;
521         int        i = 0;
522         struct     buffer_ctx storebuf;
523         DBT        key;
524         DBT        data;
525         uint64_t   keyid = 0;
526         uint32_t   shortkeyid = 0;
527         uint64_t  *subkeyids = NULL;
528         char     **uids = NULL;
529         char      *primary = NULL;
530         unsigned char worddb_data[12];
531         struct ll *wordlist = NULL;
532         struct ll *curword  = NULL;
533         bool       deadlock = false;
534
535         keyid = get_keyid(publickey);
536
537         if (!intrans) {
538                 starttrans();
539         }
540
541         /*
542          * Delete the key if we already have it.
543          *
544          * TODO: Can we optimize this perhaps? Possibly when other data is
545          * involved as well? I suspect this is easiest and doesn't make a lot
546          * of difference though - the largest chunk of data is the keydata and
547          * it definitely needs updated.
548          */
549         if (update) {
550                 deadlock = (delete_key(keyid, true) == -1);
551         }
552
553         /*
554          * Convert the key to a flat set of binary data.
555          */
556         if (!deadlock) {
557                 next = publickey->next;
558                 publickey->next = NULL;
559                 flatten_publickey(publickey, &packets, &list_end);
560                 publickey->next = next;
561
562                 storebuf.offset = 0; 
563                 storebuf.size = 8192;
564                 storebuf.buffer = malloc(8192);
565         
566                 write_openpgp_stream(buffer_putchar, &storebuf, packets);
567
568                 /*
569                  * Now we have the key data store it in the DB; the keyid is
570                  * the key.
571                  */
572                 memset(&key, 0, sizeof(key));
573                 memset(&data, 0, sizeof(data));
574                 key.data = &keyid;
575                 key.size = sizeof(keyid);
576                 data.size = storebuf.offset;
577                 data.data = storebuf.buffer;
578
579                 ret = keydb(keyid)->put(keydb(keyid),
580                                 txn,
581                                 &key,
582                                 &data,
583                                 0); /* flags*/
584                 if (ret != 0) {
585                         logthing(LOGTHING_ERROR,
586                                         "Problem storing key: %s",
587                                         db_strerror(ret));
588                         if (ret == DB_LOCK_DEADLOCK) {
589                                 deadlock = true;
590                         }
591                 }
592
593                 free(storebuf.buffer);
594                 storebuf.buffer = NULL;
595                 storebuf.size = 0;
596                 storebuf.offset = 0; 
597         
598                 free_packet_list(packets);
599                 packets = NULL;
600         }
601
602         /*
603          * Walk through our uids storing the words into the db with the keyid.
604          */
605         if (!deadlock) {
606                 uids = keyuids(publickey, &primary);
607         }
608         if (uids != NULL) {
609                 for (i = 0; ret == 0 && uids[i] != NULL; i++) {
610                         wordlist = makewordlist(wordlist, uids[i]);
611                 }
612
613                 for (curword = wordlist; curword != NULL && !deadlock;
614                                 curword = curword->next) {
615                         memset(&key, 0, sizeof(key));
616                         memset(&data, 0, sizeof(data));
617                         key.data = curword->object;
618                         key.size = strlen(key.data);
619                         data.data = worddb_data;
620                         data.size = sizeof(worddb_data);
621
622                         /*
623                          * Our data is the key creation time followed by the
624                          * key id.
625                          */
626                         worddb_data[ 0] = publickey->publickey->data[1];
627                         worddb_data[ 1] = publickey->publickey->data[2];
628                         worddb_data[ 2] = publickey->publickey->data[3];
629                         worddb_data[ 3] = publickey->publickey->data[4];
630                         worddb_data[ 4] = (keyid >> 56) & 0xFF;
631                         worddb_data[ 5] = (keyid >> 48) & 0xFF;
632                         worddb_data[ 6] = (keyid >> 40) & 0xFF;
633                         worddb_data[ 7] = (keyid >> 32) & 0xFF;
634                         worddb_data[ 8] = (keyid >> 24) & 0xFF;
635                         worddb_data[ 9] = (keyid >> 16) & 0xFF;
636                         worddb_data[10] = (keyid >>  8) & 0xFF;
637                         worddb_data[11] = keyid & 0xFF; 
638                         ret = worddb->put(worddb,
639                                 txn,
640                                 &key,
641                                 &data,
642                                 0);
643                         if (ret != 0) {
644                                 logthing(LOGTHING_ERROR,
645                                         "Problem storing word: %s",
646                                         db_strerror(ret));
647                                 if (ret == DB_LOCK_DEADLOCK) {
648                                         deadlock = true;
649                                 }
650                         }
651                 }
652
653                 /*
654                  * Free our UID and word lists.
655                  */
656                 llfree(wordlist, NULL);
657                 for (i = 0; uids[i] != NULL; i++) {
658                         free(uids[i]);
659                         uids[i] = NULL;
660                 }
661                 free(uids);
662                 uids = NULL;
663         }
664
665         /*
666          * Write the truncated 32 bit keyid so we can lookup the full id for
667          * queries.
668          */
669         if (!deadlock) {
670                 shortkeyid = keyid & 0xFFFFFFFF;
671
672                 memset(&key, 0, sizeof(key));
673                 memset(&data, 0, sizeof(data));
674                 key.data = &shortkeyid;
675                 key.size = sizeof(shortkeyid);
676                 data.data = &keyid;
677                 data.size = sizeof(keyid);
678
679                 ret = id32db->put(id32db,
680                         txn,
681                         &key,
682                         &data,
683                         0);
684                 if (ret != 0) {
685                         logthing(LOGTHING_ERROR,
686                                 "Problem storing short keyid: %s",
687                                 db_strerror(ret));
688                         if (ret == DB_LOCK_DEADLOCK) {
689                                 deadlock = true;
690                         }
691                 }
692         }
693
694         if (!deadlock) {
695                 subkeyids = keysubkeys(publickey);
696                 i = 0;
697                 while (subkeyids != NULL && subkeyids[i] != 0) {
698                         shortkeyid = subkeyids[i++] & 0xFFFFFFFF;
699
700                         memset(&key, 0, sizeof(key));
701                         memset(&data, 0, sizeof(data));
702                         key.data = &shortkeyid;
703                         key.size = sizeof(shortkeyid);
704                         data.data = &keyid;
705                         data.size = sizeof(keyid);
706
707                         ret = id32db->put(id32db,
708                                 txn,
709                                 &key,
710                                 &data,
711                                 0);
712                         if (ret != 0) {
713                                 logthing(LOGTHING_ERROR,
714                                         "Problem storing short keyid: %s",
715                                         db_strerror(ret));
716                                 if (ret == DB_LOCK_DEADLOCK) {
717                                         deadlock = true;
718                                 }
719                         }
720                 }
721                 if (subkeyids != NULL) {
722                         free(subkeyids);
723                         subkeyids = NULL;
724                 }
725         }
726
727         if (!intrans) {
728                 endtrans();
729         }
730
731         return deadlock ? -1 : 0 ;
732 }
733
734 /**
735  *      delete_key - Given a keyid delete the key from storage.
736  *      @keyid: The keyid to delete.
737  *      @intrans: If we're already in a transaction.
738  *
739  *      This function deletes a public key from whatever storage mechanism we
740  *      are using. Returns 0 if the key existed.
741  */
742 int delete_key(uint64_t keyid, bool intrans)
743 {
744         struct openpgp_publickey *publickey = NULL;
745         DBT key, data;
746         DBC *cursor = NULL;
747         uint32_t   shortkeyid = 0;
748         uint64_t  *subkeyids = NULL;
749         int ret = 0;
750         int i;
751         char **uids = NULL;
752         char *primary = NULL;
753         unsigned char worddb_data[12];
754         struct ll *wordlist = NULL;
755         struct ll *curword  = NULL;
756         bool deadlock = false;
757
758         if (!intrans) {
759                 starttrans();
760         }
761
762         fetch_key(keyid, &publickey, true);
763
764         /*
765          * Walk through the uids removing the words from the worddb.
766          */
767         if (publickey != NULL) {
768                 uids = keyuids(publickey, &primary);
769         }
770         if (uids != NULL) {
771                 for (i = 0; ret == 0 && uids[i] != NULL; i++) {
772                         wordlist = makewordlist(wordlist, uids[i]);
773                 }
774                                 
775                 ret = worddb->cursor(worddb,
776                         txn,
777                         &cursor,
778                         0);   /* flags */
779
780                 for (curword = wordlist; curword != NULL && !deadlock;
781                                 curword = curword->next) {
782                         memset(&key, 0, sizeof(key));
783                         memset(&data, 0, sizeof(data));
784                         key.data = curword->object;
785                         key.size = strlen(key.data);
786                         data.data = worddb_data;
787                         data.size = sizeof(worddb_data);
788
789                         /*
790                          * Our data is the key creation time followed by the
791                          * key id.
792                          */
793                         worddb_data[ 0] = publickey->publickey->data[1];
794                         worddb_data[ 1] = publickey->publickey->data[2];
795                         worddb_data[ 2] = publickey->publickey->data[3];
796                         worddb_data[ 3] = publickey->publickey->data[4];
797                         worddb_data[ 4] = (keyid >> 56) & 0xFF;
798                         worddb_data[ 5] = (keyid >> 48) & 0xFF;
799                         worddb_data[ 6] = (keyid >> 40) & 0xFF;
800                         worddb_data[ 7] = (keyid >> 32) & 0xFF;
801                         worddb_data[ 8] = (keyid >> 24) & 0xFF;
802                         worddb_data[ 9] = (keyid >> 16) & 0xFF;
803                         worddb_data[10] = (keyid >>  8) & 0xFF;
804                         worddb_data[11] = keyid & 0xFF; 
805
806                         ret = cursor->c_get(cursor,
807                                 &key,
808                                 &data,
809                                 DB_GET_BOTH);
810
811                         if (ret == 0) {
812                                 ret = cursor->c_del(cursor, 0);
813                                 if (ret != 0) {
814                                         logthing(LOGTHING_ERROR,
815                                                 "Problem deleting word: %s",
816                                                 db_strerror(ret));
817                                 }
818                         }
819
820                         if (ret != 0) {
821                                 logthing(LOGTHING_ERROR,
822                                         "Problem deleting word: %s",
823                                         db_strerror(ret));
824                                 if (ret == DB_LOCK_DEADLOCK) {
825                                         deadlock = true;
826                                 }
827                         }
828                 }
829                 ret = cursor->c_close(cursor);
830                 cursor = NULL;
831
832                 /*
833                  * Free our UID and word lists.
834                  */
835                 llfree(wordlist, NULL);
836                 for (i = 0; uids[i] != NULL; i++) {
837                         free(uids[i]);
838                         uids[i] = NULL;
839                 }
840                 free(uids);
841                 uids = NULL;
842                 free_publickey(publickey);
843                 publickey = NULL;
844         }
845
846         if (!deadlock) {
847                 ret = id32db->cursor(id32db,
848                         txn,
849                         &cursor,
850                         0);   /* flags */
851
852                 shortkeyid = keyid & 0xFFFFFFFF;
853
854                 memset(&key, 0, sizeof(key));
855                 memset(&data, 0, sizeof(data));
856                 key.data = &shortkeyid;
857                 key.size = sizeof(shortkeyid);
858                 data.data = &keyid;
859                 data.size = sizeof(keyid);
860
861                 ret = cursor->c_get(cursor,
862                         &key,
863                         &data,
864                         DB_GET_BOTH);
865
866                 if (ret == 0) {
867                         ret = cursor->c_del(cursor, 0);
868                         if (ret != 0) {
869                                 logthing(LOGTHING_ERROR,
870                                         "Problem deleting short keyid: %s",
871                                         db_strerror(ret));
872                         }
873                 }
874
875                 if (ret != 0) {
876                         logthing(LOGTHING_ERROR,
877                                 "Problem deleting short keyid: %s",
878                                 db_strerror(ret));
879                         if (ret == DB_LOCK_DEADLOCK) {
880                                 deadlock = true;
881                         }
882                 }
883
884                 subkeyids = keysubkeys(publickey);
885                 i = 0;
886                 while (subkeyids != NULL && subkeyids[i] != 0) {
887                         shortkeyid = subkeyids[i++] & 0xFFFFFFFF;
888
889                         memset(&key, 0, sizeof(key));
890                         memset(&data, 0, sizeof(data));
891                         key.data = &shortkeyid;
892                         key.size = sizeof(shortkeyid);
893                         data.data = &keyid;
894                         data.size = sizeof(keyid);
895
896                         ret = cursor->c_get(cursor,
897                                 &key,
898                                 &data,
899                                 DB_GET_BOTH);
900
901                         if (ret == 0) {
902                                 ret = cursor->c_del(cursor, 0);
903                                 if (ret != 0) {
904                                         logthing(LOGTHING_ERROR,
905                                                 "Problem deleting short"
906                                                 " keyid: %s",
907                                                 db_strerror(ret));
908                                 }
909                         }
910
911                         if (ret != 0) {
912                                 logthing(LOGTHING_ERROR,
913                                         "Problem deleting short keyid: %s",
914                                         db_strerror(ret));
915                                 if (ret == DB_LOCK_DEADLOCK) {
916                                         deadlock = true;
917                                 }
918                         }
919                 }
920                 if (subkeyids != NULL) {
921                         free(subkeyids);
922                         subkeyids = NULL;
923                 }
924
925                 ret = cursor->c_close(cursor);
926                 cursor = NULL;
927         }
928
929         if (!deadlock) {
930                 key.data = &keyid;
931                 key.size = sizeof(keyid);
932
933                 keydb(keyid)->del(keydb(keyid),
934                                 txn,
935                                 &key,
936                                 0); /* flags */
937         }
938
939         if (!intrans) {
940                 endtrans();
941         }
942
943         return deadlock ? (-1) : (ret == DB_NOTFOUND);
944 }
945
946 /**
947  *      iterate_keys - call a function once for each key in the db.
948  *      @iterfunc: The function to call.
949  *      @ctx: A context pointer
950  *
951  *      Calls iterfunc once for each key in the database. ctx is passed
952  *      unaltered to iterfunc. This function is intended to aid database dumps
953  *      and statistic calculations.
954  *
955  *      Returns the number of keys we iterated over.
956  */
957 int iterate_keys(void (*iterfunc)(void *ctx, struct openpgp_publickey *key),
958                 void *ctx)
959 {
960         DBT                         dbkey, data;
961         DBC                        *cursor = NULL;
962         int                         ret = 0;
963         int                         i = 0;
964         int                         numkeys = 0;
965         struct buffer_ctx           fetchbuf;
966         struct openpgp_packet_list *packets = NULL;
967         struct openpgp_publickey   *key = NULL;
968
969         for (i = 0; i < numdbs; i++) {
970                 ret = dbconns[i]->cursor(dbconns[i],
971                         NULL,
972                         &cursor,
973                         0);   /* flags */
974
975                 memset(&dbkey, 0, sizeof(dbkey));
976                 memset(&data, 0, sizeof(data));
977                 ret = cursor->c_get(cursor, &dbkey, &data, DB_NEXT);
978                 while (ret == 0) {
979                         fetchbuf.buffer = data.data;
980                         fetchbuf.offset = 0;
981                         fetchbuf.size = data.size;
982                         read_openpgp_stream(buffer_fetchchar, &fetchbuf,
983                                 &packets, 0);
984                         parse_keys(packets, &key);
985
986                         iterfunc(ctx, key);
987                         
988                         free_publickey(key);
989                         key = NULL;
990                         free_packet_list(packets);
991                         packets = NULL;
992                         
993                         memset(&dbkey, 0, sizeof(dbkey));
994                         memset(&data, 0, sizeof(data));
995                         ret = cursor->c_get(cursor, &dbkey, &data,
996                                         DB_NEXT);
997                         numkeys++;
998                 }
999                 if (ret != DB_NOTFOUND) {
1000                         logthing(LOGTHING_ERROR,
1001                                 "Problem reading key: %s",
1002                                 db_strerror(ret));
1003                 }
1004
1005                 ret = cursor->c_close(cursor);
1006                 cursor = NULL;
1007         }
1008         
1009         return numkeys;
1010 }
1011
1012 /**
1013  *      getfullkeyid - Maps a 32bit key id to a 64bit one.
1014  *      @keyid: The 32bit keyid.
1015  *
1016  *      This function maps a 32bit key id to the full 64bit one. It returns the
1017  *      full keyid. If the key isn't found a keyid of 0 is returned.
1018  */
1019 uint64_t getfullkeyid(uint64_t keyid)
1020 {
1021         DBT       key, data;
1022         DBC      *cursor = NULL;
1023         uint32_t  shortkeyid = 0;
1024         int       ret = 0;
1025
1026         if (keyid < 0x100000000LL) {
1027                 ret = id32db->cursor(id32db,
1028                                 txn,
1029                                 &cursor,
1030                                 0);   /* flags */
1031
1032                 shortkeyid = keyid & 0xFFFFFFFF;
1033
1034                 memset(&key, 0, sizeof(key));
1035                 memset(&data, 0, sizeof(data));
1036                 key.data = &shortkeyid;
1037                 key.size = sizeof(shortkeyid);
1038                 data.flags = DB_DBT_MALLOC;
1039
1040                 ret = cursor->c_get(cursor,
1041                         &key,
1042                         &data,
1043                         DB_SET);
1044
1045                 if (ret == 0) {
1046                         keyid = *(uint64_t *) data.data;
1047
1048                         if (data.data != NULL) {
1049                                 free(data.data);
1050                                 data.data = NULL;
1051                         }
1052                 }
1053
1054                 ret = cursor->c_close(cursor);
1055                 cursor = NULL;
1056         }
1057         
1058         return keyid;
1059 }
1060
1061 /*
1062  * Include the basic keydb routines.
1063  */
1064 #define NEED_GETKEYSIGS 1
1065 #define NEED_KEYID2UID 1
1066 #define NEED_UPDATEKEYS 1
1067 #include "keydb.c"