2 * keydb_db4.c - Routines to store and fetch keys in a DB3 database.
4 * Jonathan McDowell <noodles@earth.li>
6 * Copyright 2002-2004 Project Purple
10 #include <sys/types.h>
22 #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");
115 ret = db_env_create(&dbenv, 0);
117 logthing(LOGTHING_CRITICAL,
118 "db_env_create: %s", db_strerror(ret));
123 * Enable deadlock detection so that we don't block indefinitely on
124 * anything. What we really want is simple 2 state locks, but I'm not
125 * sure how to make the standard DB functions do that yet.
127 ret = dbenv->set_lk_detect(dbenv, DB_LOCK_DEFAULT);
129 logthing(LOGTHING_CRITICAL,
130 "db_env_create: %s", db_strerror(ret));
134 ret = dbenv->open(dbenv, config.db_dir,
135 DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_LOCK |
140 logthing(LOGTHING_CRITICAL,
141 "Error opening db environment: %s (%s)",
149 for (i = 0; i < numdbs; i++) {
150 ret = db_create(&dbconns[i], dbenv, 0);
152 logthing(LOGTHING_CRITICAL,
153 "db_create: %s", db_strerror(ret));
157 snprintf(buf, 1023, "keydb.%d.db", i);
162 ret = dbconns[i]->open(dbconns[i],
170 logthing(LOGTHING_CRITICAL,
171 "Error opening key database: %s (%s)",
178 ret = db_create(&worddb, dbenv, 0);
180 logthing(LOGTHING_CRITICAL, "db_create: %s", db_strerror(ret));
183 ret = worddb->set_flags(worddb, DB_DUP);
185 ret = worddb->open(worddb, txn, "worddb", "worddb", DB_BTREE,
189 logthing(LOGTHING_CRITICAL,
190 "Error opening word database: %s (%s)",
196 ret = db_create(&id32db, dbenv, 0);
198 logthing(LOGTHING_CRITICAL, "db_create: %s", db_strerror(ret));
201 ret = id32db->set_flags(id32db, DB_DUP);
203 ret = id32db->open(id32db, txn, "id32db", "id32db", DB_HASH,
207 logthing(LOGTHING_CRITICAL,
208 "Error opening id32 database: %s (%s)",
219 * cleanupdb - De-initialize the key database.
221 * This function should be called upon program exit to allow the DB to
222 * cleanup after itself.
228 dbenv->txn_checkpoint(dbenv, 0, 0, 0);
229 id32db->close(id32db, 0);
231 worddb->close(worddb, 0);
233 for (i = 0; i < numdbs; i++) {
234 dbconns[i]->close(dbconns[i], 0);
237 dbenv->close(dbenv, 0);
242 * starttrans - Start a transaction.
244 * Start a transaction. Intended to be used if we're about to perform many
245 * operations on the database to help speed it all up, or if we want
246 * something to only succeed if all relevant operations are successful.
248 bool starttrans(void)
252 assert(dbenv != NULL);
255 ret = dbenv->txn_begin(dbenv,
256 NULL, /* No parent transaction */
260 logthing(LOGTHING_CRITICAL,
261 "Error starting transaction: %s",
270 * endtrans - End a transaction.
272 * Ends a transaction.
278 assert(dbenv != NULL);
281 ret = txn->commit(txn,
284 logthing(LOGTHING_CRITICAL,
285 "Error ending transaction: %s",
295 * fetch_key - Given a keyid fetch the key from storage.
296 * @keyid: The keyid to fetch.
297 * @publickey: A pointer to a structure to return the key in.
298 * @intrans: If we're already in a transaction.
300 * We use the hex representation of the keyid as the filename to fetch the
301 * key from. The key is stored in the file as a binary OpenPGP stream of
302 * packets, so we can just use read_openpgp_stream() to read the packets
303 * in and then parse_keys() to parse the packets into a publickey
306 int fetch_key(uint64_t keyid, struct openpgp_publickey **publickey,
309 struct openpgp_packet_list *packets = NULL;
313 struct buffer_ctx fetchbuf;
315 if (keyid < 0x100000000LL) {
316 keyid = getfullkeyid(keyid);
319 memset(&key, 0, sizeof(key));
320 memset(&data, 0, sizeof(data));
325 key.size = sizeof(keyid);
332 ret = keydb(keyid)->get(keydb(keyid),
339 fetchbuf.buffer = data.data;
341 fetchbuf.size = data.size;
342 read_openpgp_stream(buffer_fetchchar, &fetchbuf,
344 parse_keys(packets, publickey);
345 free_packet_list(packets);
348 } else if (ret != DB_NOTFOUND) {
349 logthing(LOGTHING_ERROR,
350 "Problem retrieving key: %s",
361 int worddb_cmp(const void *d1, const void *d2)
363 return memcmp(d1, d2, 12);
367 * fetch_key_text - Trys to find the keys that contain the supplied text.
368 * @search: The text to search for.
369 * @publickey: A pointer to a structure to return the key in.
371 * This function searches for the supplied text and returns the keys that
374 int fetch_key_text(const char *search, struct openpgp_publickey **publickey)
382 char *searchtext = NULL;
383 struct ll *wordlist = NULL;
384 struct ll *curword = NULL;
385 struct ll *keylist = NULL;
386 struct ll *newkeylist = NULL;
389 searchtext = strdup(search);
390 wordlist = makewordlist(wordlist, searchtext);
394 ret = worddb->cursor(worddb,
399 for (curword = wordlist; curword != NULL; curword = curword->next) {
400 memset(&key, 0, sizeof(key));
401 memset(&data, 0, sizeof(data));
402 key.data = curword->object;
403 key.size = strlen(curword->object);
404 data.flags = DB_DBT_MALLOC;
405 ret = cursor->c_get(cursor,
409 while (ret == 0 && strncmp(key.data, curword->object,
411 ((char *) curword->object)[key.size] == 0) {
413 for (i = 4; i < 12; i++) {
415 keyid += ((unsigned char *)
419 if (keylist == NULL ||
420 llfind(keylist, data.data,
421 worddb_cmp) != NULL) {
422 newkeylist = lladd(newkeylist, data.data);
428 ret = cursor->c_get(cursor,
433 llfree(keylist, free);
434 keylist = newkeylist;
436 if (data.data != NULL) {
441 llfree(wordlist, NULL);
444 for (newkeylist = keylist;
445 newkeylist != NULL && numkeys < config.maxkeys;
446 newkeylist = newkeylist->next) {
449 for (i = 4; i < 12; i++) {
451 keyid += ((unsigned char *)
452 newkeylist->object)[i];
455 numkeys += fetch_key(keyid,
459 llfree(keylist, free);
464 ret = cursor->c_close(cursor);
473 * store_key - Takes a key and stores it.
474 * @publickey: A pointer to the public key to store.
475 * @intrans: If we're already in a transaction.
476 * @update: If true the key exists and should be updated.
478 * Again we just use the hex representation of the keyid as the filename
479 * to store the key to. We flatten the public key to a list of OpenPGP
480 * packets and then use write_openpgp_stream() to write the stream out to
481 * the file. If update is true then we delete the old key first, otherwise
482 * we trust that it doesn't exist.
484 int store_key(struct openpgp_publickey *publickey, bool intrans, bool update)
486 struct openpgp_packet_list *packets = NULL;
487 struct openpgp_packet_list *list_end = NULL;
488 struct openpgp_publickey *next = NULL;
491 struct buffer_ctx storebuf;
495 uint32_t shortkeyid = 0;
496 uint64_t *subkeyids = NULL;
498 char *primary = NULL;
499 unsigned char worddb_data[12];
500 struct ll *wordlist = NULL;
501 struct ll *curword = NULL;
502 bool deadlock = false;
504 keyid = get_keyid(publickey);
511 * Delete the key if we already have it.
513 * TODO: Can we optimize this perhaps? Possibly when other data is
514 * involved as well? I suspect this is easiest and doesn't make a lot
515 * of difference though - the largest chunk of data is the keydata and
516 * it definitely needs updated.
519 deadlock = (delete_key(keyid, true) == -1);
523 * Convert the key to a flat set of binary data.
526 next = publickey->next;
527 publickey->next = NULL;
528 flatten_publickey(publickey, &packets, &list_end);
529 publickey->next = next;
532 storebuf.size = 8192;
533 storebuf.buffer = malloc(8192);
535 write_openpgp_stream(buffer_putchar, &storebuf, packets);
538 * Now we have the key data store it in the DB; the keyid is
541 memset(&key, 0, sizeof(key));
542 memset(&data, 0, sizeof(data));
544 key.size = sizeof(keyid);
545 data.size = storebuf.offset;
546 data.data = storebuf.buffer;
548 ret = keydb(keyid)->put(keydb(keyid),
554 logthing(LOGTHING_ERROR,
555 "Problem storing key: %s",
557 if (ret == DB_LOCK_DEADLOCK) {
562 free(storebuf.buffer);
563 storebuf.buffer = NULL;
567 free_packet_list(packets);
572 * Walk through our uids storing the words into the db with the keyid.
575 uids = keyuids(publickey, &primary);
578 for (i = 0; ret == 0 && uids[i] != NULL; i++) {
579 wordlist = makewordlist(wordlist, uids[i]);
582 for (curword = wordlist; curword != NULL && !deadlock;
583 curword = curword->next) {
584 memset(&key, 0, sizeof(key));
585 memset(&data, 0, sizeof(data));
586 key.data = curword->object;
587 key.size = strlen(key.data);
588 data.data = worddb_data;
589 data.size = sizeof(worddb_data);
592 * Our data is the key creation time followed by the
595 worddb_data[ 0] = publickey->publickey->data[1];
596 worddb_data[ 1] = publickey->publickey->data[2];
597 worddb_data[ 2] = publickey->publickey->data[3];
598 worddb_data[ 3] = publickey->publickey->data[4];
599 worddb_data[ 4] = (keyid >> 56) & 0xFF;
600 worddb_data[ 5] = (keyid >> 48) & 0xFF;
601 worddb_data[ 6] = (keyid >> 40) & 0xFF;
602 worddb_data[ 7] = (keyid >> 32) & 0xFF;
603 worddb_data[ 8] = (keyid >> 24) & 0xFF;
604 worddb_data[ 9] = (keyid >> 16) & 0xFF;
605 worddb_data[10] = (keyid >> 8) & 0xFF;
606 worddb_data[11] = keyid & 0xFF;
607 ret = worddb->put(worddb,
613 logthing(LOGTHING_ERROR,
614 "Problem storing word: %s",
616 if (ret == DB_LOCK_DEADLOCK) {
623 * Free our UID and word lists.
625 llfree(wordlist, NULL);
626 for (i = 0; uids[i] != NULL; i++) {
639 * Write the truncated 32 bit keyid so we can lookup the full id for
643 shortkeyid = keyid & 0xFFFFFFFF;
645 memset(&key, 0, sizeof(key));
646 memset(&data, 0, sizeof(data));
647 key.data = &shortkeyid;
648 key.size = sizeof(shortkeyid);
650 data.size = sizeof(keyid);
652 ret = id32db->put(id32db,
658 logthing(LOGTHING_ERROR,
659 "Problem storing short keyid: %s",
661 if (ret == DB_LOCK_DEADLOCK) {
668 subkeyids = keysubkeys(publickey);
670 while (subkeyids != NULL && subkeyids[i] != 0) {
671 shortkeyid = subkeyids[i++] & 0xFFFFFFFF;
673 memset(&key, 0, sizeof(key));
674 memset(&data, 0, sizeof(data));
675 key.data = &shortkeyid;
676 key.size = sizeof(shortkeyid);
678 data.size = sizeof(keyid);
680 ret = id32db->put(id32db,
686 logthing(LOGTHING_ERROR,
687 "Problem storing short keyid: %s",
689 if (ret == DB_LOCK_DEADLOCK) {
694 if (subkeyids != NULL) {
700 return deadlock ? -1 : 0 ;
704 * delete_key - Given a keyid delete the key from storage.
705 * @keyid: The keyid to delete.
706 * @intrans: If we're already in a transaction.
708 * This function deletes a public key from whatever storage mechanism we
709 * are using. Returns 0 if the key existed.
711 int delete_key(uint64_t keyid, bool intrans)
713 struct openpgp_publickey *publickey = NULL;
716 uint32_t shortkeyid = 0;
717 uint64_t *subkeyids = NULL;
721 char *primary = NULL;
722 unsigned char worddb_data[12];
723 struct ll *wordlist = NULL;
724 struct ll *curword = NULL;
725 bool deadlock = false;
731 fetch_key(keyid, &publickey, true);
734 * Walk through the uids removing the words from the worddb.
736 if (publickey != NULL) {
737 uids = keyuids(publickey, &primary);
740 for (i = 0; ret == 0 && uids[i] != NULL; i++) {
741 wordlist = makewordlist(wordlist, uids[i]);
744 ret = worddb->cursor(worddb,
749 for (curword = wordlist; curword != NULL && !deadlock;
750 curword = curword->next) {
751 memset(&key, 0, sizeof(key));
752 memset(&data, 0, sizeof(data));
753 key.data = curword->object;
754 key.size = strlen(key.data);
755 data.data = worddb_data;
756 data.size = sizeof(worddb_data);
759 * Our data is the key creation time followed by the
762 worddb_data[ 0] = publickey->publickey->data[1];
763 worddb_data[ 1] = publickey->publickey->data[2];
764 worddb_data[ 2] = publickey->publickey->data[3];
765 worddb_data[ 3] = publickey->publickey->data[4];
766 worddb_data[ 4] = (keyid >> 56) & 0xFF;
767 worddb_data[ 5] = (keyid >> 48) & 0xFF;
768 worddb_data[ 6] = (keyid >> 40) & 0xFF;
769 worddb_data[ 7] = (keyid >> 32) & 0xFF;
770 worddb_data[ 8] = (keyid >> 24) & 0xFF;
771 worddb_data[ 9] = (keyid >> 16) & 0xFF;
772 worddb_data[10] = (keyid >> 8) & 0xFF;
773 worddb_data[11] = keyid & 0xFF;
775 ret = cursor->c_get(cursor,
781 ret = cursor->c_del(cursor, 0);
783 logthing(LOGTHING_ERROR,
784 "Problem deleting word: %s",
790 logthing(LOGTHING_ERROR,
791 "Problem deleting word: %s",
793 if (ret == DB_LOCK_DEADLOCK) {
798 ret = cursor->c_close(cursor);
802 * Free our UID and word lists.
804 llfree(wordlist, NULL);
805 for (i = 0; uids[i] != NULL; i++) {
811 free_publickey(publickey);
816 ret = id32db->cursor(id32db,
821 shortkeyid = keyid & 0xFFFFFFFF;
823 memset(&key, 0, sizeof(key));
824 memset(&data, 0, sizeof(data));
825 key.data = &shortkeyid;
826 key.size = sizeof(shortkeyid);
828 data.size = sizeof(keyid);
830 ret = cursor->c_get(cursor,
836 ret = cursor->c_del(cursor, 0);
838 logthing(LOGTHING_ERROR,
839 "Problem deleting short keyid: %s",
845 logthing(LOGTHING_ERROR,
846 "Problem deleting short keyid: %s",
848 if (ret == DB_LOCK_DEADLOCK) {
853 subkeyids = keysubkeys(publickey);
855 while (subkeyids != NULL && subkeyids[i] != 0) {
856 shortkeyid = subkeyids[i++] & 0xFFFFFFFF;
858 memset(&key, 0, sizeof(key));
859 memset(&data, 0, sizeof(data));
860 key.data = &shortkeyid;
861 key.size = sizeof(shortkeyid);
863 data.size = sizeof(keyid);
865 ret = cursor->c_get(cursor,
871 ret = cursor->c_del(cursor, 0);
873 logthing(LOGTHING_ERROR,
874 "Problem deleting short"
881 logthing(LOGTHING_ERROR,
882 "Problem deleting short keyid: %s",
884 if (ret == DB_LOCK_DEADLOCK) {
889 if (subkeyids != NULL) {
894 ret = cursor->c_close(cursor);
900 key.size = sizeof(keyid);
902 keydb(keyid)->del(keydb(keyid),
912 return deadlock ? (-1) : (ret == DB_NOTFOUND);
916 * dumpdb - dump the key database
917 * @filenamebase: The base filename to use for the dump.
919 * Dumps the database into one or more files, which contain pure OpenPGP
920 * that can be reimported into onak or gpg. filenamebase provides a base
921 * file name for the dump; several files may be created, all of which will
922 * begin with this string and then have a unique number and a .pgp
925 int dumpdb(char *filenamebase)
935 for (i = 0; i < numdbs; i++) {
936 ret = dbconns[i]->cursor(dbconns[i],
941 snprintf(filename, 1023, "%s.%d.pgp", filenamebase, i);
942 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0640);
944 logthing(LOGTHING_ERROR,
945 "Error opening keydump file (%s): %s",
949 memset(&key, 0, sizeof(key));
950 memset(&data, 0, sizeof(data));
951 ret = cursor->c_get(cursor, &key, &data, DB_NEXT);
953 write(fd, data.data, data.size);
954 memset(&key, 0, sizeof(key));
955 memset(&data, 0, sizeof(data));
956 ret = cursor->c_get(cursor, &key, &data,
959 if (ret != DB_NOTFOUND) {
960 logthing(LOGTHING_ERROR,
961 "Problem reading key: %s",
967 ret = cursor->c_close(cursor);
975 * getfullkeyid - Maps a 32bit key id to a 64bit one.
976 * @keyid: The 32bit keyid.
978 * This function maps a 32bit key id to the full 64bit one. It returns the
979 * full keyid. If the key isn't found a keyid of 0 is returned.
981 uint64_t getfullkeyid(uint64_t keyid)
985 uint32_t shortkeyid = 0;
988 if (keyid < 0x100000000LL) {
989 ret = id32db->cursor(id32db,
994 shortkeyid = keyid & 0xFFFFFFFF;
996 memset(&key, 0, sizeof(key));
997 memset(&data, 0, sizeof(data));
998 key.data = &shortkeyid;
999 key.size = sizeof(shortkeyid);
1000 data.flags = DB_DBT_MALLOC;
1002 ret = cursor->c_get(cursor,
1008 keyid = *(uint64_t *) data.data;
1010 if (data.data != NULL) {
1016 ret = cursor->c_close(cursor);
1024 * Include the basic keydb routines.
1026 #define NEED_GETKEYSIGS 1
1027 #define NEED_KEYID2UID 1