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