2 * keydb_db4.c - Routines to store and fetch keys in a DB4 database.
4 * Jonathan McDowell <noodles@earth.li>
6 * Copyright 2002-2004 Project Purple
21 #include "charfuncs.h"
25 #include "decodekey.h"
26 #include "keystructs.h"
29 #include "onak-conf.h"
34 * dbenv - our database environment.
36 static DB_ENV *dbenv = NULL;
39 * numdb - The number of database files we have.
41 static int numdbs = 16;
44 * dbconn - our connections to the key database files.
46 static DB **dbconns = NULL;
49 * worddb - our connection to the word database.
51 static DB *worddb = NULL;
54 * id32db - our connection to the 32bit ID database.
56 static DB *id32db = NULL;
59 * txn - our current transaction id.
61 static DB_TXN *txn = NULL;
63 DB *keydb(uint64_t keyid)
69 return(dbconns[keytrun % numdbs]);
73 * initdb - Initialize the key database.
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
79 void initdb(bool readonly)
87 snprintf(buf, sizeof(buf) - 1, "%s/num_keydb", config.db_dir);
88 numdb = fopen(buf, "r");
90 if (fgets(buf, sizeof(buf), numdb) != NULL) {
94 } else if (!readonly) {
95 logthing(LOGTHING_ERROR, "Couldn't open num_keydb: %s",
97 numdb = fopen(buf, "w");
99 fprintf(numdb, "%d", numdbs);
102 logthing(LOGTHING_ERROR,
103 "Couldn't write num_keydb: %s",
108 dbconns = malloc(sizeof (DB *) * numdbs);
109 if (dbconns == NULL) {
110 logthing(LOGTHING_CRITICAL,
111 "Couldn't allocate memory for dbconns");
116 ret = db_env_create(&dbenv, 0);
118 logthing(LOGTHING_CRITICAL,
119 "db_env_create: %s", db_strerror(ret));
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.
129 ret = dbenv->set_lk_detect(dbenv, DB_LOCK_DEFAULT);
131 logthing(LOGTHING_CRITICAL,
132 "db_env_create: %s", db_strerror(ret));
137 ret = dbenv->open(dbenv, config.db_dir,
138 DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_LOCK |
143 logthing(LOGTHING_CRITICAL,
144 "Error opening db environment: %s (%s)",
147 dbenv->close(dbenv, 0);
155 for (i = 0; !ret && i < numdbs; i++) {
156 ret = db_create(&dbconns[i], dbenv, 0);
158 logthing(LOGTHING_CRITICAL,
159 "db_create: %s", db_strerror(ret));
163 snprintf(buf, 1023, "keydb.%d.db", i);
168 ret = dbconns[i]->open(dbconns[i],
176 logthing(LOGTHING_CRITICAL,
177 "Error opening key database:"
188 ret = db_create(&worddb, dbenv, 0);
190 logthing(LOGTHING_CRITICAL, "db_create: %s",
196 ret = worddb->set_flags(worddb, DB_DUP);
200 ret = worddb->open(worddb, txn, "worddb", "worddb", DB_BTREE,
204 logthing(LOGTHING_CRITICAL,
205 "Error opening word database: %s (%s)",
212 ret = db_create(&id32db, dbenv, 0);
214 logthing(LOGTHING_CRITICAL, "db_create: %s",
220 ret = id32db->set_flags(id32db, DB_DUP);
224 ret = id32db->open(id32db, txn, "id32db", "id32db", DB_HASH,
228 logthing(LOGTHING_CRITICAL,
229 "Error opening id32 database: %s (%s)",
241 logthing(LOGTHING_CRITICAL,
242 "Error opening database; exiting");
250 * cleanupdb - De-initialize the key database.
252 * This function should be called upon program exit to allow the DB to
253 * cleanup after itself.
260 dbenv->txn_checkpoint(dbenv, 0, 0, 0);
261 if (id32db != NULL) {
262 id32db->close(id32db, 0);
265 if (worddb != NULL) {
266 worddb->close(worddb, 0);
269 for (i = 0; i < numdbs; i++) {
270 if (dbconns[i] != NULL) {
271 dbconns[i]->close(dbconns[i], 0);
277 dbenv->close(dbenv, 0);
283 * starttrans - Start a transaction.
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.
289 bool starttrans(void)
293 log_assert(dbenv != NULL);
294 log_assert(txn == NULL);
296 ret = dbenv->txn_begin(dbenv,
297 NULL, /* No parent transaction */
301 logthing(LOGTHING_CRITICAL,
302 "Error starting transaction: %s",
311 * endtrans - End a transaction.
313 * Ends a transaction.
319 log_assert(dbenv != NULL);
320 log_assert(txn != NULL);
322 ret = txn->commit(txn,
325 logthing(LOGTHING_CRITICAL,
326 "Error ending transaction: %s",
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.
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
347 int fetch_key(uint64_t keyid, struct openpgp_publickey **publickey,
350 struct openpgp_packet_list *packets = NULL;
354 struct buffer_ctx fetchbuf;
356 if (keyid < 0x100000000LL) {
357 keyid = getfullkeyid(keyid);
360 memset(&key, 0, sizeof(key));
361 memset(&data, 0, sizeof(data));
366 key.size = sizeof(keyid);
373 ret = keydb(keyid)->get(keydb(keyid),
380 fetchbuf.buffer = data.data;
382 fetchbuf.size = data.size;
383 read_openpgp_stream(buffer_fetchchar, &fetchbuf,
385 parse_keys(packets, publickey);
386 free_packet_list(packets);
389 } else if (ret != DB_NOTFOUND) {
390 logthing(LOGTHING_ERROR,
391 "Problem retrieving key: %s",
402 int worddb_cmp(const void *d1, const void *d2)
404 return memcmp(d1, d2, 12);
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.
412 * This function searches for the supplied text and returns the keys that
415 int fetch_key_text(const char *search, struct openpgp_publickey **publickey)
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 };
430 searchtext = strdup(search);
431 wordlist = makewordlist(wordlist, searchtext);
433 for (curword = wordlist; curword != NULL; curword = curword->next) {
436 ret = worddb->cursor(worddb,
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,
450 while (ret == 0 && strncmp(key.data, curword->object,
452 ((char *) curword->object)[key.size] == 0) {
454 for (i = 4; i < 12; i++) {
456 keyid += ((unsigned char *)
460 if (keylist.count == 0 ||
461 array_find(&keylist, keyid)) {
462 array_add(&newkeylist, keyid);
468 ret = cursor->c_get(cursor,
473 array_free(&keylist);
474 keylist = newkeylist;
475 newkeylist.keys = NULL;
476 newkeylist.count = newkeylist.size = 0;
477 if (data.data != NULL) {
481 ret = cursor->c_close(cursor);
485 llfree(wordlist, NULL);
489 for (i = 0; i < keylist.count; i++) {
490 numkeys += fetch_key(keylist.keys[i],
494 array_free(&keylist);
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.
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.
515 int store_key(struct openpgp_publickey *publickey, bool intrans, bool update)
517 struct openpgp_packet_list *packets = NULL;
518 struct openpgp_packet_list *list_end = NULL;
519 struct openpgp_publickey *next = NULL;
522 struct buffer_ctx storebuf;
526 uint32_t shortkeyid = 0;
527 uint64_t *subkeyids = 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;
535 keyid = get_keyid(publickey);
542 * Delete the key if we already have it.
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.
550 deadlock = (delete_key(keyid, true) == -1);
554 * Convert the key to a flat set of binary data.
557 next = publickey->next;
558 publickey->next = NULL;
559 flatten_publickey(publickey, &packets, &list_end);
560 publickey->next = next;
563 storebuf.size = 8192;
564 storebuf.buffer = malloc(8192);
566 write_openpgp_stream(buffer_putchar, &storebuf, packets);
569 * Now we have the key data store it in the DB; the keyid is
572 memset(&key, 0, sizeof(key));
573 memset(&data, 0, sizeof(data));
575 key.size = sizeof(keyid);
576 data.size = storebuf.offset;
577 data.data = storebuf.buffer;
579 ret = keydb(keyid)->put(keydb(keyid),
585 logthing(LOGTHING_ERROR,
586 "Problem storing key: %s",
588 if (ret == DB_LOCK_DEADLOCK) {
593 free(storebuf.buffer);
594 storebuf.buffer = NULL;
598 free_packet_list(packets);
603 * Walk through our uids storing the words into the db with the keyid.
606 uids = keyuids(publickey, &primary);
609 for (i = 0; ret == 0 && uids[i] != NULL; i++) {
610 wordlist = makewordlist(wordlist, uids[i]);
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);
623 * Our data is the key creation time followed by the
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,
644 logthing(LOGTHING_ERROR,
645 "Problem storing word: %s",
647 if (ret == DB_LOCK_DEADLOCK) {
654 * Free our UID and word lists.
656 llfree(wordlist, NULL);
657 for (i = 0; uids[i] != NULL; i++) {
666 * Write the truncated 32 bit keyid so we can lookup the full id for
670 shortkeyid = keyid & 0xFFFFFFFF;
672 memset(&key, 0, sizeof(key));
673 memset(&data, 0, sizeof(data));
674 key.data = &shortkeyid;
675 key.size = sizeof(shortkeyid);
677 data.size = sizeof(keyid);
679 ret = id32db->put(id32db,
685 logthing(LOGTHING_ERROR,
686 "Problem storing short keyid: %s",
688 if (ret == DB_LOCK_DEADLOCK) {
695 subkeyids = keysubkeys(publickey);
697 while (subkeyids != NULL && subkeyids[i] != 0) {
698 shortkeyid = subkeyids[i++] & 0xFFFFFFFF;
700 memset(&key, 0, sizeof(key));
701 memset(&data, 0, sizeof(data));
702 key.data = &shortkeyid;
703 key.size = sizeof(shortkeyid);
705 data.size = sizeof(keyid);
707 ret = id32db->put(id32db,
713 logthing(LOGTHING_ERROR,
714 "Problem storing short keyid: %s",
716 if (ret == DB_LOCK_DEADLOCK) {
721 if (subkeyids != NULL) {
731 return deadlock ? -1 : 0 ;
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.
739 * This function deletes a public key from whatever storage mechanism we
740 * are using. Returns 0 if the key existed.
742 int delete_key(uint64_t keyid, bool intrans)
744 struct openpgp_publickey *publickey = NULL;
747 uint32_t shortkeyid = 0;
748 uint64_t *subkeyids = 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;
762 fetch_key(keyid, &publickey, true);
765 * Walk through the uids removing the words from the worddb.
767 if (publickey != NULL) {
768 uids = keyuids(publickey, &primary);
771 for (i = 0; ret == 0 && uids[i] != NULL; i++) {
772 wordlist = makewordlist(wordlist, uids[i]);
775 ret = worddb->cursor(worddb,
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);
790 * Our data is the key creation time followed by the
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;
806 ret = cursor->c_get(cursor,
812 ret = cursor->c_del(cursor, 0);
814 logthing(LOGTHING_ERROR,
815 "Problem deleting word: %s",
821 logthing(LOGTHING_ERROR,
822 "Problem deleting word: %s",
824 if (ret == DB_LOCK_DEADLOCK) {
829 ret = cursor->c_close(cursor);
833 * Free our UID and word lists.
835 llfree(wordlist, NULL);
836 for (i = 0; uids[i] != NULL; i++) {
842 free_publickey(publickey);
847 ret = id32db->cursor(id32db,
852 shortkeyid = keyid & 0xFFFFFFFF;
854 memset(&key, 0, sizeof(key));
855 memset(&data, 0, sizeof(data));
856 key.data = &shortkeyid;
857 key.size = sizeof(shortkeyid);
859 data.size = sizeof(keyid);
861 ret = cursor->c_get(cursor,
867 ret = cursor->c_del(cursor, 0);
869 logthing(LOGTHING_ERROR,
870 "Problem deleting short keyid: %s",
876 logthing(LOGTHING_ERROR,
877 "Problem deleting short keyid: %s",
879 if (ret == DB_LOCK_DEADLOCK) {
884 subkeyids = keysubkeys(publickey);
886 while (subkeyids != NULL && subkeyids[i] != 0) {
887 shortkeyid = subkeyids[i++] & 0xFFFFFFFF;
889 memset(&key, 0, sizeof(key));
890 memset(&data, 0, sizeof(data));
891 key.data = &shortkeyid;
892 key.size = sizeof(shortkeyid);
894 data.size = sizeof(keyid);
896 ret = cursor->c_get(cursor,
902 ret = cursor->c_del(cursor, 0);
904 logthing(LOGTHING_ERROR,
905 "Problem deleting short"
912 logthing(LOGTHING_ERROR,
913 "Problem deleting short keyid: %s",
915 if (ret == DB_LOCK_DEADLOCK) {
920 if (subkeyids != NULL) {
925 ret = cursor->c_close(cursor);
931 key.size = sizeof(keyid);
933 keydb(keyid)->del(keydb(keyid),
943 return deadlock ? (-1) : (ret == DB_NOTFOUND);
947 * iterate_keys - call a function once for each key in the db.
948 * @iterfunc: The function to call.
949 * @ctx: A context pointer
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.
955 * Returns the number of keys we iterated over.
957 int iterate_keys(void (*iterfunc)(void *ctx, struct openpgp_publickey *key),
965 struct buffer_ctx fetchbuf;
966 struct openpgp_packet_list *packets = NULL;
967 struct openpgp_publickey *key = NULL;
969 for (i = 0; i < numdbs; i++) {
970 ret = dbconns[i]->cursor(dbconns[i],
975 memset(&dbkey, 0, sizeof(dbkey));
976 memset(&data, 0, sizeof(data));
977 ret = cursor->c_get(cursor, &dbkey, &data, DB_NEXT);
979 fetchbuf.buffer = data.data;
981 fetchbuf.size = data.size;
982 read_openpgp_stream(buffer_fetchchar, &fetchbuf,
984 parse_keys(packets, &key);
990 free_packet_list(packets);
993 memset(&dbkey, 0, sizeof(dbkey));
994 memset(&data, 0, sizeof(data));
995 ret = cursor->c_get(cursor, &dbkey, &data,
999 if (ret != DB_NOTFOUND) {
1000 logthing(LOGTHING_ERROR,
1001 "Problem reading key: %s",
1005 ret = cursor->c_close(cursor);
1013 * getfullkeyid - Maps a 32bit key id to a 64bit one.
1014 * @keyid: The 32bit keyid.
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.
1019 uint64_t getfullkeyid(uint64_t keyid)
1023 uint32_t shortkeyid = 0;
1026 if (keyid < 0x100000000LL) {
1027 ret = id32db->cursor(id32db,
1032 shortkeyid = keyid & 0xFFFFFFFF;
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;
1040 ret = cursor->c_get(cursor,
1046 keyid = *(uint64_t *) data.data;
1048 if (data.data != NULL) {
1054 ret = cursor->c_close(cursor);
1062 * Include the basic keydb routines.
1064 #define NEED_GETKEYSIGS 1
1065 #define NEED_KEYID2UID 1
1066 #define NEED_UPDATEKEYS 1