]> git.sommitrealweird.co.uk Git - onak.git/blob - keydb_db3.c
309a29747d81082e4bb834fd9c61707fc1007724
[onak.git] / keydb_db3.c
1 /*
2  * keydb_db3.c - Routines to store and fetch keys in a DB3 database.
3  *
4  * Jonathan McDowell <noodles@earth.li>
5  *
6  * Copyright 2002 Project Purple
7  *
8  * $Id: keydb_db3.c,v 1.21 2003/10/03 23:02:04 noodles Exp $
9  */
10
11 #include <assert.h>
12 #include <sys/types.h>
13 #include <sys/uio.h>
14 #include <ctype.h>
15 #include <errno.h>
16 #include <fcntl.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21
22 #include <db.h>
23
24 #include "charfuncs.h"
25 #include "keydb.h"
26 #include "keyid.h"
27 #include "decodekey.h"
28 #include "keystructs.h"
29 #include "mem.h"
30 #include "log.h"
31 #include "onak-conf.h"
32 #include "parsekey.h"
33
34 /**
35  *      dbenv - our database environment.
36  */
37 static DB_ENV *dbenv = NULL;
38
39 /**
40  *      numdb - The number of database files we have.
41  */
42 static int numdbs = 16;
43
44 /**
45  *      dbconn - our connections to the key database files.
46  */
47 static DB **dbconns = NULL;
48
49 /**
50  *      worddb - our connection to the word database.
51  */
52 static DB *worddb = NULL;
53
54 /**
55  *      txn - our current transaction id.
56  */
57 static DB_TXN *txn = NULL;
58
59 DB *keydb(uint64_t keyid)
60 {
61         uint64_t keytrun;
62
63         keytrun = keyid >> 8;
64
65         return(dbconns[keytrun % numdbs]);
66 }
67
68 /**
69  *      makewordlist - Takes a string and splits it into a set of unique words.
70  *      @wordlist: The current word list.
71  *      @words: The string to split and add.
72  *
73  *      We take words and split it on non alpha numeric characters. These get
74  *      added to the word list if they're not already present. If the wordlist
75  *      is NULL then we start a new list, otherwise it's search for already
76  *      added words. Note that words is modified in the process of scanning.
77  *
78  *      Returns the new word list.
79  */
80 struct ll *makewordlist(struct ll *wordlist, char *word)
81 {
82         char *start = NULL;
83         char *end = NULL;
84
85         /*
86          * Walk through the words string, spliting on non alphanumerics and
87          * then checking if the word already exists in the list. If not then
88          * we add it.
89          */
90         end = word;
91         while (end != NULL && *end != 0) {
92                 start = end;
93                 while (*start != 0 && !isalnum(*start)) {
94                         start++;
95                 }
96                 end = start;
97                 while (*end != 0 && isalnum(*end)) {
98                         *end = tolower(*end);
99                         end++;
100                 }
101                 if (end - start > 1) {
102                         if (*end != 0) {
103                                 *end = 0;
104                                 end++;
105                         }
106                         
107                         if (llfind(wordlist, start,
108                                         strcmp) == NULL) {
109                                 wordlist = lladd(wordlist,
110                                                 start);
111                         }
112                 }
113         }
114
115         return wordlist;
116 }
117
118 /**
119  *      initdb - Initialize the key database.
120  *
121  *      This function should be called before any of the other functions in
122  *      this file are called in order to allow the DB to be initialized ready
123  *      for access.
124  */
125 void initdb(void)
126 {
127         char  buf[1024];
128         FILE *numdb = NULL;
129         int   ret = 0;
130         int   i = 0;
131
132         snprintf(buf, sizeof(buf) - 1, "%s/num_keydb", config.db_dir);
133         numdb = fopen(buf, "r");
134         if (numdb != NULL) {
135                 if (fgets(buf, sizeof(buf), numdb) != NULL) {
136                         numdbs = atoi(buf);
137                 }
138                 fclose(numdb);
139         } else {
140                 logthing(LOGTHING_ERROR, "Couldn't open num_keydb: %s",
141                                 strerror(errno));
142         }
143
144         dbconns = malloc(sizeof (DB *) * numdbs);
145         if (dbconns == NULL) {
146                 logthing(LOGTHING_CRITICAL,
147                                 "Couldn't allocate memory for dbconns");
148                 exit(1);
149         }
150
151         ret = db_env_create(&dbenv, 0);
152         if (ret != 0) {
153                 logthing(LOGTHING_CRITICAL,
154                         "db_env_create: %s", db_strerror(ret));
155                 exit(1);
156         }
157
158         /*
159          * Enable deadlock detection so that we don't block indefinitely on
160          * anything. What we really want is simple 2 state locks, but I'm not
161          * sure how to make the standard DB functions do that yet.
162          */
163         ret = dbenv->set_lk_detect(dbenv, DB_LOCK_DEFAULT);
164         if (ret != 0) {
165                 logthing(LOGTHING_CRITICAL,
166                         "db_env_create: %s", db_strerror(ret));
167                 exit(1);
168         }
169
170         ret = dbenv->open(dbenv, config.db_dir,
171                         DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_LOCK |
172                         DB_INIT_TXN |
173                         DB_CREATE,
174                         0);
175         if (ret != 0) {
176                 logthing(LOGTHING_CRITICAL,
177                                 "Error opening db environment: %s (%s)",
178                                 config.db_dir,
179                                 db_strerror(ret));
180                 exit(1);
181         }
182
183         for (i = 0; i < numdbs; i++) {
184                 ret = db_create(&dbconns[i], dbenv, 0);
185                 if (ret != 0) {
186                         logthing(LOGTHING_CRITICAL,
187                                 "db_create: %s", db_strerror(ret));
188                         exit(1);
189                 }
190
191                 snprintf(buf, 1023, "keydb.%d.db", i);
192                 ret = dbconns[i]->open(dbconns[i], buf,
193                         NULL,
194                         DB_HASH,
195                         DB_CREATE,
196                         0664);
197                 if (ret != 0) {
198                         logthing(LOGTHING_CRITICAL,
199                                 "Error opening key database: %s (%s)",
200                                 buf,
201                                 db_strerror(ret));
202                         exit(1);
203                 }
204         }
205
206         ret = db_create(&worddb, dbenv, 0);
207         if (ret != 0) {
208                 logthing(LOGTHING_CRITICAL, "db_create: %s", db_strerror(ret));
209                 exit(1);
210         }
211         ret = worddb->set_flags(worddb, DB_DUP);
212
213         ret = worddb->open(worddb, "worddb", NULL, DB_BTREE,
214                         DB_CREATE,
215                         0664);
216         if (ret != 0) {
217                 logthing(LOGTHING_CRITICAL,
218                                 "Error opening word database: %s (%s)",
219                                 "worddb",
220                                 db_strerror(ret));
221                 exit(1);
222         }
223         
224         return;
225 }
226
227 /**
228  *      cleanupdb - De-initialize the key database.
229  *
230  *      This function should be called upon program exit to allow the DB to
231  *      cleanup after itself.
232  */
233 void cleanupdb(void)
234 {
235         int i = 0;
236
237         txn_checkpoint(dbenv, 0, 0, 0);
238         worddb->close(worddb, 0);
239         worddb = NULL;
240         for (i = 0; i < numdbs; i++) {
241                 dbconns[i]->close(dbconns[i], 0);
242                 dbconns[i] = NULL;
243         }
244         dbenv->close(dbenv, 0);
245         dbenv = NULL;
246 }
247
248 /**
249  *      starttrans - Start a transaction.
250  *
251  *      Start a transaction. Intended to be used if we're about to perform many
252  *      operations on the database to help speed it all up, or if we want
253  *      something to only succeed if all relevant operations are successful.
254  */
255 bool starttrans(void)
256 {
257         int ret;
258
259         assert(dbenv != NULL);
260         assert(txn == NULL);
261
262         ret = txn_begin(dbenv,
263                 NULL, /* No parent transaction */
264                 &txn,
265                 0);
266         if (ret != 0) {
267                 logthing(LOGTHING_CRITICAL,
268                                 "Error starting transaction: %s",
269                                 db_strerror(ret));
270                 exit(1);
271         }
272
273         return true;
274 }
275
276 /**
277  *      endtrans - End a transaction.
278  *
279  *      Ends a transaction.
280  */
281 void endtrans(void)
282 {
283         int ret;
284
285         assert(dbenv != NULL);
286         assert(txn != NULL);
287
288         ret = txn_commit(txn,
289                 0);
290         if (ret != 0) {
291                 logthing(LOGTHING_CRITICAL,
292                                 "Error ending transaction: %s",
293                                 db_strerror(ret));
294                 exit(1);
295         }
296         txn = NULL;
297
298         return;
299 }
300
301 /**
302  *      fetch_key - Given a keyid fetch the key from storage.
303  *      @keyid: The keyid to fetch.
304  *      @publickey: A pointer to a structure to return the key in.
305  *      @intrans: If we're already in a transaction.
306  *
307  *      We use the hex representation of the keyid as the filename to fetch the
308  *      key from. The key is stored in the file as a binary OpenPGP stream of
309  *      packets, so we can just use read_openpgp_stream() to read the packets
310  *      in and then parse_keys() to parse the packets into a publickey
311  *      structure.
312  */
313 int fetch_key(uint64_t keyid, struct openpgp_publickey **publickey,
314                 bool intrans)
315 {
316         struct openpgp_packet_list *packets = NULL;
317         DBT key, data;
318         int ret = 0;
319         int numkeys = 0;
320         struct buffer_ctx fetchbuf;
321
322         memset(&key, 0, sizeof(key));
323         memset(&data, 0, sizeof(data));
324
325         data.size = 0;
326         data.data = NULL;
327
328         key.size = sizeof(keyid);
329         key.data = &keyid;
330         keyid &= 0xFFFFFFFF;
331
332         if (!intrans) {
333                 starttrans();
334         }
335
336         ret = keydb(keyid)->get(keydb(keyid),
337                         txn,
338                         &key,
339                         &data,
340                         0); /* flags*/
341         
342         if (ret == 0) {
343                 fetchbuf.buffer = data.data;
344                 fetchbuf.offset = 0;
345                 fetchbuf.size = data.size;
346                 read_openpgp_stream(buffer_fetchchar, &fetchbuf,
347                                 &packets, 0);
348                 parse_keys(packets, publickey);
349                 free_packet_list(packets);
350                 packets = NULL;
351                 numkeys++;
352         } else if (ret != DB_NOTFOUND) {
353                 logthing(LOGTHING_ERROR,
354                                 "Problem retrieving key: %s",
355                                 db_strerror(ret));
356         }
357
358         if (!intrans) {
359                 endtrans();
360         }
361
362         return (numkeys);
363 }
364
365 int worddb_cmp(const char *d1, const char *d2)
366 {
367         return memcmp(d1, d2, 12);
368 }
369
370 /**
371  *      fetch_key_text - Trys to find the keys that contain the supplied text.
372  *      @search: The text to search for.
373  *      @publickey: A pointer to a structure to return the key in.
374  *
375  *      This function searches for the supplied text and returns the keys that
376  *      contain it.
377  */
378 int fetch_key_text(const char *search, struct openpgp_publickey **publickey)
379 {
380         DBC *cursor = NULL;
381         DBT key, data;
382         int ret;
383         uint64_t keyid;
384         int i;
385         int numkeys;
386         char *searchtext = NULL;
387         struct ll *wordlist = NULL;
388         struct ll *curword = NULL;
389         struct ll *keylist = NULL;
390         struct ll *newkeylist = NULL;
391
392         numkeys = 0;
393         searchtext = strdup(search);
394         wordlist = makewordlist(wordlist, searchtext);
395
396         starttrans();
397
398         ret = worddb->cursor(worddb,
399                         txn,
400                         &cursor,
401                         0);   /* flags */
402
403         for (curword = wordlist; curword != NULL; curword = curword->next) {
404                 memset(&key, 0, sizeof(key));
405                 memset(&data, 0, sizeof(data));
406                 key.data = curword->object;
407                 key.size = strlen(curword->object);
408                 data.flags = DB_DBT_MALLOC;
409                 ret = cursor->c_get(cursor,
410                                 &key,
411                                 &data,
412                                 DB_SET);
413                 while (ret == 0 && strncmp(key.data, curword->object,
414                                         key.size) == 0 &&
415                                 ((char *) curword->object)[key.size] == 0) {
416                         keyid = 0;
417                         for (i = 4; i < 12; i++) {
418                                 keyid <<= 8;
419                                 keyid += ((unsigned char *)
420                                                 data.data)[i];
421                         }
422
423                         if (keylist == NULL ||
424                                         llfind(keylist, data.data,
425                                                 worddb_cmp) != NULL) {
426                                 newkeylist = lladd(newkeylist, data.data);
427                                 data.data = NULL;
428                         } else {
429                                 free(data.data);
430                                 data.data = NULL;
431                         }
432                         ret = cursor->c_get(cursor,
433                                         &key,
434                                         &data,
435                                         DB_NEXT);
436                 }
437                 llfree(keylist, free);
438                 keylist = newkeylist;
439                 newkeylist = NULL;
440                 if (data.data != NULL) {
441                         free(data.data);
442                         data.data = NULL;
443                 }
444         }
445         llfree(wordlist, NULL);
446         wordlist = NULL;
447         
448         for (newkeylist = keylist;
449                         newkeylist != NULL && numkeys < config.maxkeys;
450                         newkeylist = newkeylist->next) {
451
452                         keyid = 0;
453                         for (i = 4; i < 12; i++) {
454                                 keyid <<= 8;
455                                 keyid += ((unsigned char *)
456                                                 newkeylist->object)[i];
457                         }
458
459                         numkeys += fetch_key(keyid,
460                                         publickey,
461                                         true);
462         }
463         llfree(keylist, free);
464         keylist = NULL;
465         free(searchtext);
466         searchtext = NULL;
467
468         ret = cursor->c_close(cursor);
469         cursor = NULL;
470
471         endtrans();
472         
473         return (numkeys);
474 }
475
476 /**
477  *      store_key - Takes a key and stores it.
478  *      @publickey: A pointer to the public key to store.
479  *      @intrans: If we're already in a transaction.
480  *      @update: If true the key exists and should be updated.
481  *
482  *      Again we just use the hex representation of the keyid as the filename
483  *      to store the key to. We flatten the public key to a list of OpenPGP
484  *      packets and then use write_openpgp_stream() to write the stream out to
485  *      the file. If update is true then we delete the old key first, otherwise
486  *      we trust that it doesn't exist.
487  */
488 int store_key(struct openpgp_publickey *publickey, bool intrans, bool update)
489 {
490         struct     openpgp_packet_list *packets = NULL;
491         struct     openpgp_packet_list *list_end = NULL;
492         struct     openpgp_publickey *next = NULL;
493         int        ret = 0;
494         int        i = 0;
495         struct     buffer_ctx storebuf;
496         DBT        key;
497         DBT        data;
498         uint64_t   keyid = 0;
499         char     **uids = NULL;
500         char      *primary = NULL;
501         unsigned char worddb_data[12];
502         struct ll *wordlist = NULL;
503         struct ll *curword  = NULL;
504         bool       deadlock = false;
505
506         keyid = get_keyid(publickey);
507
508         if (!intrans) {
509                 starttrans();
510         }
511
512         /*
513          * Delete the key if we already have it.
514          *
515          * TODO: Can we optimize this perhaps? Possibly when other data is
516          * involved as well? I suspect this is easiest and doesn't make a lot
517          * of difference though - the largest chunk of data is the keydata and
518          * it definitely needs updated.
519          */
520         if (update) {
521                 deadlock = (delete_key(keyid, true) == -1);
522         }
523
524         /*
525          * Convert the key to a flat set of binary data.
526          */
527         if (!deadlock) {
528                 next = publickey->next;
529                 publickey->next = NULL;
530                 flatten_publickey(publickey, &packets, &list_end);
531                 publickey->next = next;
532
533                 storebuf.offset = 0; 
534                 storebuf.size = 8192;
535                 storebuf.buffer = malloc(8192);
536         
537                 write_openpgp_stream(buffer_putchar, &storebuf, packets);
538
539                 /*
540                  * Now we have the key data store it in the DB; the keyid is
541                  * the key.
542                  */
543                 memset(&key, 0, sizeof(key));
544                 memset(&data, 0, sizeof(data));
545                 key.data = &keyid;
546                 key.size = sizeof(keyid);
547                 keyid &= 0xFFFFFFFF;
548                 data.size = storebuf.offset;
549                 data.data = storebuf.buffer;
550
551                 ret = keydb(keyid)->put(keydb(keyid),
552                                 txn,
553                                 &key,
554                                 &data,
555                                 0); /* flags*/
556                 if (ret != 0) {
557                         logthing(LOGTHING_ERROR,
558                                         "Problem storing key: %s",
559                                         db_strerror(ret));
560                         if (ret == DB_LOCK_DEADLOCK) {
561                                 deadlock = true;
562                         }
563                 }
564
565                 free(storebuf.buffer);
566                 storebuf.buffer = NULL;
567                 storebuf.size = 0;
568                 storebuf.offset = 0; 
569         
570                 free_packet_list(packets);
571                 packets = NULL;
572         }
573
574         /*
575          * Walk through our uids storing the words into the db with the keyid.
576          */
577         if (!deadlock) {
578                 uids = keyuids(publickey, &primary);
579         }
580         if (uids != NULL) {
581                 for (i = 0; ret == 0 && uids[i] != NULL; i++) {
582                         wordlist = makewordlist(wordlist, uids[i]);
583                 }
584
585                 for (curword = wordlist; curword != NULL && !deadlock;
586                                 curword = curword->next) {
587                         memset(&key, 0, sizeof(key));
588                         memset(&data, 0, sizeof(data));
589                         key.data = curword->object;
590                         key.size = strlen(key.data);
591                         data.data = worddb_data;
592                         data.size = sizeof(worddb_data);
593
594                         /*
595                          * Our data is the key creation time followed by the
596                          * key id.
597                          */
598                         worddb_data[ 0] = publickey->publickey->data[1];
599                         worddb_data[ 1] = publickey->publickey->data[2];
600                         worddb_data[ 2] = publickey->publickey->data[3];
601                         worddb_data[ 3] = publickey->publickey->data[4];
602                         worddb_data[ 4] = (keyid >> 56) & 0xFF;
603                         worddb_data[ 5] = (keyid >> 48) & 0xFF;
604                         worddb_data[ 6] = (keyid >> 40) & 0xFF;
605                         worddb_data[ 7] = (keyid >> 32) & 0xFF;
606                         worddb_data[ 8] = (keyid >> 24) & 0xFF;
607                         worddb_data[ 9] = (keyid >> 16) & 0xFF;
608                         worddb_data[10] = (keyid >>  8) & 0xFF;
609                         worddb_data[11] = keyid & 0xFF; 
610                         ret = worddb->put(worddb,
611                                 txn,
612                                 &key,
613                                 &data,
614                                 0);
615                         if (ret != 0) {
616                                 logthing(LOGTHING_ERROR,
617                                         "Problem storing word: %s",
618                                         db_strerror(ret));
619                                 if (ret == DB_LOCK_DEADLOCK) {
620                                         deadlock = true;
621                                 }
622                         }
623                 }
624
625                 /*
626                  * Free our UID and word lists.
627                  */
628                 llfree(wordlist, NULL);
629                 for (i = 0; uids[i] != NULL; i++) {
630                         free(uids[i]);
631                         uids[i] = NULL;
632                 }
633                 free(uids);
634                 uids = NULL;
635         }
636
637         if (!intrans) {
638                 endtrans();
639         }
640
641         return deadlock ? -1 : 0 ;
642 }
643
644 /**
645  *      delete_key - Given a keyid delete the key from storage.
646  *      @keyid: The keyid to delete.
647  *      @intrans: If we're already in a transaction.
648  *
649  *      This function deletes a public key from whatever storage mechanism we
650  *      are using. Returns 0 if the key existed.
651  */
652 int delete_key(uint64_t keyid, bool intrans)
653 {
654         struct openpgp_publickey *publickey = NULL;
655         DBT key, data;
656         DBC *cursor = NULL;
657         int ret = 0;
658         int i;
659         char **uids = NULL;
660         char *primary = NULL;
661         unsigned char worddb_data[12];
662         struct ll *wordlist = NULL;
663         struct ll *curword  = NULL;
664         bool deadlock = false;
665
666         keyid &= 0xFFFFFFFF;
667
668         if (!intrans) {
669                 starttrans();
670         }
671
672         fetch_key(keyid, &publickey, true);
673
674         /*
675          * Walk through the uids removing the words from the worddb.
676          */
677         if (publickey != NULL) {
678                 uids = keyuids(publickey, &primary);
679         }
680         if (uids != NULL) {
681                 for (i = 0; ret == 0 && uids[i] != NULL; i++) {
682                         wordlist = makewordlist(wordlist, uids[i]);
683                 }
684                                 
685                 ret = worddb->cursor(worddb,
686                         txn,
687                         &cursor,
688                         0);   /* flags */
689
690                 for (curword = wordlist; curword != NULL && !deadlock;
691                                 curword = curword->next) {
692                         memset(&key, 0, sizeof(key));
693                         memset(&data, 0, sizeof(data));
694                         key.data = curword->object;
695                         key.size = strlen(key.data);
696                         data.data = worddb_data;
697                         data.size = sizeof(worddb_data);
698
699                         /*
700                          * Our data is the key creation time followed by the
701                          * key id.
702                          */
703                         worddb_data[ 0] = publickey->publickey->data[1];
704                         worddb_data[ 1] = publickey->publickey->data[2];
705                         worddb_data[ 2] = publickey->publickey->data[3];
706                         worddb_data[ 3] = publickey->publickey->data[4];
707                         worddb_data[ 4] = (keyid >> 56) & 0xFF;
708                         worddb_data[ 5] = (keyid >> 48) & 0xFF;
709                         worddb_data[ 6] = (keyid >> 40) & 0xFF;
710                         worddb_data[ 7] = (keyid >> 32) & 0xFF;
711                         worddb_data[ 8] = (keyid >> 24) & 0xFF;
712                         worddb_data[ 9] = (keyid >> 16) & 0xFF;
713                         worddb_data[10] = (keyid >>  8) & 0xFF;
714                         worddb_data[11] = keyid & 0xFF; 
715
716                         ret = cursor->c_get(cursor,
717                                 &key,
718                                 &data,
719                                 DB_GET_BOTH);
720
721                         if (ret == 0) {
722                                 ret = cursor->c_del(cursor, 0);
723                                 if (ret != 0) {
724                                         logthing(LOGTHING_ERROR,
725                                                 "Problem deleting word: %s",
726                                                 db_strerror(ret));
727                                 }
728                         }
729
730                         if (ret != 0) {
731                                 logthing(LOGTHING_ERROR,
732                                         "Problem deleting word: %s",
733                                         db_strerror(ret));
734                                 if (ret == DB_LOCK_DEADLOCK) {
735                                         deadlock = true;
736                                 }
737                         }
738                 }
739                 ret = cursor->c_close(cursor);
740                 cursor = NULL;
741
742                 /*
743                  * Free our UID and word lists.
744                  */
745                 llfree(wordlist, NULL);
746                 for (i = 0; uids[i] != NULL; i++) {
747                         free(uids[i]);
748                         uids[i] = NULL;
749                 }
750                 free(uids);
751                 uids = NULL;
752                 free_publickey(publickey);
753                 publickey = NULL;
754         }
755
756         if (!deadlock) {
757                 key.data = &keyid;
758                 key.size = sizeof(keyid);
759
760                 keydb(keyid)->del(keydb(keyid),
761                                 txn,
762                                 &key,
763                                 0); /* flags */
764         }
765
766         if (!intrans) {
767                 endtrans();
768         }
769
770         return deadlock ? (-1) : (ret == DB_NOTFOUND);
771 }
772
773 /**
774  *      dumpdb - dump the key database
775  *      @filenamebase: The base filename to use for the dump.
776  *
777  *      Dumps the database into one or more files, which contain pure OpenPGP
778  *      that can be reimported into onak or gpg. filenamebase provides a base
779  *      file name for the dump; several files may be created, all of which will
780  *      begin with this string and then have a unique number and a .pgp
781  *      extension.
782  */
783 int dumpdb(char *filenamebase)
784 {
785         DBT   key, data;
786         DBC  *cursor = NULL;
787         int   ret = 0;
788         int   fd = -1;
789         int   i = 0;
790         char  filename[1024];
791
792         filename[1023] = 0;
793         for (i = 0; i < numdbs; i++) {
794                 ret = dbconns[i]->cursor(dbconns[i],
795                         NULL,
796                         &cursor,
797                         0);   /* flags */
798
799                 snprintf(filename, 1023, "%s.%d.pgp", filenamebase, i);
800                 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0640);
801                 if (fd == -1) {
802                         logthing(LOGTHING_ERROR,
803                                 "Error opening keydump file (%s): %s",
804                                 filename,
805                                 strerror(errno));
806                 } else {
807                         memset(&key, 0, sizeof(key));
808                         memset(&data, 0, sizeof(data));
809                         ret = cursor->c_get(cursor, &key, &data, DB_NEXT);
810                         while (ret == 0) {
811                                 write(fd, data.data, data.size);
812                                 memset(&key, 0, sizeof(key));
813                                 memset(&data, 0, sizeof(data));
814                                 ret = cursor->c_get(cursor, &key, &data,
815                                                 DB_NEXT);
816                         }
817                         if (ret != DB_NOTFOUND) {
818                                 logthing(LOGTHING_ERROR,
819                                         "Problem reading key: %s",
820                                         db_strerror(ret));
821                         }
822                         close(fd);
823                 }
824
825                 ret = cursor->c_close(cursor);
826                 cursor = NULL;
827         }
828         
829         return 0;
830 }
831
832 /*
833  * Include the basic keydb routines.
834  */
835 #define NEED_GETFULLKEYID 1
836 #define NEED_GETKEYSIGS 1
837 #define NEED_KEYID2UID 1
838 #include "keydb.c"