2 * keydb_db4.c - Routines to store and fetch keys in a DB4 database.
4 * Copyright 2002-2008 Jonathan McDowell <noodles@earth.li>
20 #include "charfuncs.h"
24 #include "decodekey.h"
25 #include "keystructs.h"
28 #include "onak-conf.h"
32 #define DB4_UPGRADE_FILE "db_upgrade.lck"
35 * dbenv - our database environment.
37 static DB_ENV *dbenv = NULL;
40 * numdb - The number of database files we have.
42 static int numdbs = 16;
45 * dbconn - our connections to the key database files.
47 static DB **dbconns = NULL;
50 * worddb - our connection to the word database.
52 static DB *worddb = NULL;
55 * id32db - our connection to the 32bit ID database.
57 static DB *id32db = NULL;
60 * skshashdb - our connection to the SKS hash database.
62 static DB *skshashdb = NULL;
65 * txn - our current transaction id.
67 static DB_TXN *txn = NULL;
69 DB *keydb(uint64_t keyid)
75 return(dbconns[keytrun % numdbs]);
79 * db4_errfunc - Direct DB errors to logfile
81 * Basic function to take errors from the DB library and output them to
82 * the logfile rather than stderr.
84 #if (DB_VERSION_MAJOR == 4) && (DB_VERSION_MINOR < 3)
85 static void db4_errfunc(const char *errpfx, const char *errmsg)
87 static void db4_errfunc(const DB_ENV *edbenv, const char *errpfx,
92 logthing(LOGTHING_DEBUG, "db4 error: %s:%s", errpfx, errmsg);
94 logthing(LOGTHING_DEBUG, "db4 error: %s", errmsg);
101 * starttrans - Start a transaction.
103 * Start a transaction. Intended to be used if we're about to perform many
104 * operations on the database to help speed it all up, or if we want
105 * something to only succeed if all relevant operations are successful.
107 static bool db4_starttrans(void)
111 log_assert(dbenv != NULL);
112 log_assert(txn == NULL);
114 ret = dbenv->txn_begin(dbenv,
115 NULL, /* No parent transaction */
119 logthing(LOGTHING_CRITICAL,
120 "Error starting transaction: %s",
129 * endtrans - End a transaction.
131 * Ends a transaction.
133 static void db4_endtrans(void)
137 log_assert(dbenv != NULL);
138 log_assert(txn != NULL);
140 ret = txn->commit(txn,
143 logthing(LOGTHING_CRITICAL,
144 "Error ending transaction: %s",
154 * cleanupdb - De-initialize the key database.
156 * This function should be called upon program exit to allow the DB to
157 * cleanup after itself.
159 static void db4_cleanupdb(void)
164 dbenv->txn_checkpoint(dbenv, 0, 0, 0);
165 if (skshashdb != NULL) {
166 skshashdb->close(skshashdb, 0);
169 if (id32db != NULL) {
170 id32db->close(id32db, 0);
173 if (worddb != NULL) {
174 worddb->close(worddb, 0);
177 for (i = 0; i < numdbs; i++) {
178 if (dbconns[i] != NULL) {
179 dbconns[i]->close(dbconns[i], 0);
185 dbenv->close(dbenv, 0);
191 * db4_upgradedb - Upgrade a DB4 database
193 * Called if we discover we need to upgrade our DB4 database; ie if
194 * we're running with a newer version of db4 than the database was
197 static int db4_upgradedb(int numdb)
206 snprintf(buf, sizeof(buf) - 1, "%s/%s", config.db_dir,
208 lockfile_fd = open(buf, O_RDWR | O_CREAT | O_EXCL, 0600);
209 if (lockfile_fd < 0) {
210 if (errno == EEXIST) {
211 while (stat(buf, &statbuf) == 0) ;
214 logthing(LOGTHING_CRITICAL, "Couldn't open database "
215 "update lock file: %s", strerror(errno));
219 snprintf(buf, sizeof(buf) - 1, "%d", getpid());
220 write(lockfile_fd, buf, strlen(buf));
223 logthing(LOGTHING_NOTICE, "Upgrading DB4 database");
224 ret = db_env_create(&dbenv, 0);
225 dbenv->set_errcall(dbenv, &db4_errfunc);
226 dbenv->remove(dbenv, config.db_dir, 0);
228 for (i = 0; i < numdb; i++) {
229 ret = db_create(&curdb, NULL, 0);
231 snprintf(buf, sizeof(buf) - 1, "%s/keydb.%d.db",
233 logthing(LOGTHING_DEBUG, "Upgrading %s", buf);
234 ret = curdb->upgrade(curdb, buf, 0);
235 curdb->close(curdb, 0);
237 logthing(LOGTHING_ERROR, "Error upgrading DB %s : %s",
243 ret = db_create(&curdb, NULL, 0);
245 snprintf(buf, sizeof(buf) - 1, "%s/worddb", config.db_dir);
246 logthing(LOGTHING_DEBUG, "Upgrading %s", buf);
247 ret = curdb->upgrade(curdb, buf, 0);
248 curdb->close(curdb, 0);
250 logthing(LOGTHING_ERROR, "Error upgrading DB %s : %s",
255 ret = db_create(&curdb, NULL, 0);
257 snprintf(buf, sizeof(buf) - 1, "%s/id32db", config.db_dir);
258 logthing(LOGTHING_DEBUG, "Upgrading %s", buf);
259 ret = curdb->upgrade(curdb, buf, 0);
260 curdb->close(curdb, 0);
262 logthing(LOGTHING_ERROR, "Error upgrading DB %s : %s",
267 ret = db_create(&curdb, NULL, 0);
269 snprintf(buf, sizeof(buf) - 1, "%s/skshashdb", config.db_dir);
270 logthing(LOGTHING_DEBUG, "Upgrading %s", buf);
271 ret = curdb->upgrade(curdb, buf, 0);
272 curdb->close(curdb, 0);
274 logthing(LOGTHING_ERROR, "Error upgrading DB %s : %s",
279 snprintf(buf, sizeof(buf) - 1, "%s/%s", config.db_dir,
287 * initdb - Initialize the key database.
289 * This function should be called before any of the other functions in
290 * this file are called in order to allow the DB to be initialized ready
293 static void db4_initdb(bool readonly)
303 snprintf(buf, sizeof(buf) - 1, "%s/%s", config.db_dir,
305 ret = stat(buf, &statbuf);
306 while ((ret == 0) || (errno != ENOENT)) {
308 logthing(LOGTHING_CRITICAL, "Couldn't stat upgrade "
309 "lock file: %s (%d)", strerror(errno), ret);
312 logthing(LOGTHING_DEBUG, "DB4 upgrade in progress; waiting.");
314 ret = stat(buf, &statbuf);
318 snprintf(buf, sizeof(buf) - 1, "%s/num_keydb", config.db_dir);
319 numdb = fopen(buf, "r");
321 if (fgets(buf, sizeof(buf), numdb) != NULL) {
325 } else if (!readonly) {
326 logthing(LOGTHING_ERROR, "Couldn't open num_keydb: %s",
328 numdb = fopen(buf, "w");
330 fprintf(numdb, "%d", numdbs);
333 logthing(LOGTHING_ERROR,
334 "Couldn't write num_keydb: %s",
339 dbconns = calloc(numdbs, sizeof (DB *));
340 if (dbconns == NULL) {
341 logthing(LOGTHING_CRITICAL,
342 "Couldn't allocate memory for dbconns");
347 ret = db_env_create(&dbenv, 0);
349 logthing(LOGTHING_CRITICAL,
350 "db_env_create: %s", db_strerror(ret));
355 * Up the number of locks we're allowed at once. We base this on
356 * the maximum number of keys we're going to return.
358 maxlocks = config.maxkeys * 16;
359 if (maxlocks < 1000) {
362 dbenv->set_lk_max_locks(dbenv, maxlocks);
363 dbenv->set_lk_max_objects(dbenv, maxlocks);
366 * Enable deadlock detection so that we don't block indefinitely on
367 * anything. What we really want is simple 2 state locks, but I'm not
368 * sure how to make the standard DB functions do that yet.
371 dbenv->set_errcall(dbenv, &db4_errfunc);
372 ret = dbenv->set_lk_detect(dbenv, DB_LOCK_DEFAULT);
374 logthing(LOGTHING_CRITICAL,
375 "db_env_create: %s", db_strerror(ret));
380 ret = dbenv->open(dbenv, config.db_dir,
381 DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_LOCK |
385 #ifdef DB_VERSION_MISMATCH
386 if (ret == DB_VERSION_MISMATCH) {
387 dbenv->close(dbenv, 0);
389 ret = db4_upgradedb(numdbs);
391 ret = db_env_create(&dbenv, 0);
394 dbenv->set_errcall(dbenv, &db4_errfunc);
395 dbenv->set_lk_detect(dbenv, DB_LOCK_DEFAULT);
396 ret = dbenv->open(dbenv, config.db_dir,
397 DB_INIT_LOG | DB_INIT_MPOOL |
398 DB_INIT_LOCK | DB_INIT_TXN |
399 DB_CREATE | DB_RECOVER,
403 dbenv->txn_checkpoint(dbenv,
412 logthing(LOGTHING_CRITICAL,
413 "Error opening db environment: %s (%s)",
416 dbenv->close(dbenv, 0);
424 for (i = 0; !ret && i < numdbs; i++) {
425 ret = db_create(&dbconns[i], dbenv, 0);
427 logthing(LOGTHING_CRITICAL,
428 "db_create: %s", db_strerror(ret));
432 snprintf(buf, 1023, "keydb.%d.db", i);
437 ret = dbconns[i]->open(dbconns[i],
445 logthing(LOGTHING_CRITICAL,
446 "Error opening key database:"
457 ret = db_create(&worddb, dbenv, 0);
459 logthing(LOGTHING_CRITICAL, "db_create: %s",
465 ret = worddb->set_flags(worddb, DB_DUP);
469 ret = worddb->open(worddb, txn, "worddb", "worddb", DB_BTREE,
473 logthing(LOGTHING_CRITICAL,
474 "Error opening word database: %s (%s)",
481 ret = db_create(&id32db, dbenv, 0);
483 logthing(LOGTHING_CRITICAL, "db_create: %s",
489 ret = id32db->set_flags(id32db, DB_DUP);
493 ret = id32db->open(id32db, txn, "id32db", "id32db", DB_HASH,
497 logthing(LOGTHING_CRITICAL,
498 "Error opening id32 database: %s (%s)",
505 ret = db_create(&skshashdb, dbenv, 0);
507 logthing(LOGTHING_CRITICAL, "db_create: %s",
513 ret = skshashdb->open(skshashdb, txn, "skshashdb",
514 "skshashdb", DB_HASH,
518 logthing(LOGTHING_CRITICAL,
519 "Error opening skshash database: %s (%s)",
531 logthing(LOGTHING_CRITICAL,
532 "Error opening database; exiting");
540 * getfullkeyid - Maps a 32bit key id to a 64bit one.
541 * @keyid: The 32bit keyid.
543 * This function maps a 32bit key id to the full 64bit one. It returns the
544 * full keyid. If the key isn't found a keyid of 0 is returned.
546 static uint64_t db4_getfullkeyid(uint64_t keyid)
550 uint32_t shortkeyid = 0;
553 if (keyid < 0x100000000LL) {
554 ret = id32db->cursor(id32db,
559 shortkeyid = keyid & 0xFFFFFFFF;
561 memset(&key, 0, sizeof(key));
562 memset(&data, 0, sizeof(data));
563 key.data = &shortkeyid;
564 key.size = sizeof(shortkeyid);
565 data.flags = DB_DBT_MALLOC;
567 ret = cursor->c_get(cursor,
573 keyid = *(uint64_t *) data.data;
575 if (data.data != NULL) {
581 ret = cursor->c_close(cursor);
589 * fetch_key - Given a keyid fetch the key from storage.
590 * @keyid: The keyid to fetch.
591 * @publickey: A pointer to a structure to return the key in.
592 * @intrans: If we're already in a transaction.
594 * We use the hex representation of the keyid as the filename to fetch the
595 * key from. The key is stored in the file as a binary OpenPGP stream of
596 * packets, so we can just use read_openpgp_stream() to read the packets
597 * in and then parse_keys() to parse the packets into a publickey
600 static int db4_fetch_key(uint64_t keyid, struct openpgp_publickey **publickey,
603 struct openpgp_packet_list *packets = NULL;
607 struct buffer_ctx fetchbuf;
609 if (keyid < 0x100000000LL) {
610 keyid = db4_getfullkeyid(keyid);
613 memset(&key, 0, sizeof(key));
614 memset(&data, 0, sizeof(data));
619 key.size = sizeof(keyid);
626 ret = keydb(keyid)->get(keydb(keyid),
633 fetchbuf.buffer = data.data;
635 fetchbuf.size = data.size;
636 read_openpgp_stream(buffer_fetchchar, &fetchbuf,
638 parse_keys(packets, publickey);
639 free_packet_list(packets);
642 } else if (ret != DB_NOTFOUND) {
643 logthing(LOGTHING_ERROR,
644 "Problem retrieving key: %s",
655 int worddb_cmp(const void *d1, const void *d2)
657 return memcmp(d1, d2, 12);
661 * fetch_key_text - Trys to find the keys that contain the supplied text.
662 * @search: The text to search for.
663 * @publickey: A pointer to a structure to return the key in.
665 * This function searches for the supplied text and returns the keys that
668 static int db4_fetch_key_text(const char *search,
669 struct openpgp_publickey **publickey)
677 char *searchtext = NULL;
678 struct ll *wordlist = NULL;
679 struct ll *curword = NULL;
680 struct keyarray keylist = { NULL, 0, 0 };
681 struct keyarray newkeylist = { NULL, 0, 0 };
685 searchtext = strdup(search);
686 wordlist = makewordlist(wordlist, searchtext);
688 for (curword = wordlist; curword != NULL; curword = curword->next) {
691 ret = worddb->cursor(worddb,
696 memset(&key, 0, sizeof(key));
697 memset(&data, 0, sizeof(data));
698 key.data = curword->object;
699 key.size = strlen(curword->object);
700 data.flags = DB_DBT_MALLOC;
701 ret = cursor->c_get(cursor,
705 while (ret == 0 && strncmp(key.data, curword->object,
707 ((char *) curword->object)[key.size] == 0) {
709 for (i = 4; i < 12; i++) {
711 keyid += ((unsigned char *)
716 * Only add the keys containing this word if this is
717 * our first pass (ie we have no existing key list),
718 * or the key contained a previous word.
720 if (firstpass || array_find(&keylist, keyid)) {
721 array_add(&newkeylist, keyid);
727 ret = cursor->c_get(cursor,
732 array_free(&keylist);
733 keylist = newkeylist;
734 newkeylist.keys = NULL;
735 newkeylist.count = newkeylist.size = 0;
736 if (data.data != NULL) {
740 ret = cursor->c_close(cursor);
745 llfree(wordlist, NULL);
748 if (keylist.count > config.maxkeys) {
749 keylist.count = config.maxkeys;
753 for (i = 0; i < keylist.count; i++) {
754 numkeys += db4_fetch_key(keylist.keys[i],
758 array_free(&keylist);
767 static int db4_fetch_key_skshash(const struct skshash *hash,
768 struct openpgp_publickey **publickey)
775 ret = skshashdb->cursor(skshashdb,
780 memset(&key, 0, sizeof(key));
781 memset(&data, 0, sizeof(data));
782 key.data = (void *) hash->hash;
783 key.size = sizeof(hash->hash);
784 data.flags = DB_DBT_MALLOC;
786 ret = cursor->c_get(cursor,
792 keyid = *(uint64_t *) data.data;
794 if (data.data != NULL) {
800 ret = cursor->c_close(cursor);
803 return db4_fetch_key(keyid, publickey, false);
807 * delete_key - Given a keyid delete the key from storage.
808 * @keyid: The keyid to delete.
809 * @intrans: If we're already in a transaction.
811 * This function deletes a public key from whatever storage mechanism we
812 * are using. Returns 0 if the key existed.
814 static int db4_delete_key(uint64_t keyid, bool intrans)
816 struct openpgp_publickey *publickey = NULL;
819 uint32_t shortkeyid = 0;
820 uint64_t *subkeyids = NULL;
824 char *primary = NULL;
825 unsigned char worddb_data[12];
826 struct ll *wordlist = NULL;
827 struct ll *curword = NULL;
828 bool deadlock = false;
835 db4_fetch_key(keyid, &publickey, true);
838 * Walk through the uids removing the words from the worddb.
840 if (publickey != NULL) {
841 uids = keyuids(publickey, &primary);
844 for (i = 0; ret == 0 && uids[i] != NULL; i++) {
845 wordlist = makewordlist(wordlist, uids[i]);
848 ret = worddb->cursor(worddb,
853 for (curword = wordlist; curword != NULL && !deadlock;
854 curword = curword->next) {
855 memset(&key, 0, sizeof(key));
856 memset(&data, 0, sizeof(data));
857 key.data = curword->object;
858 key.size = strlen(key.data);
859 data.data = worddb_data;
860 data.size = sizeof(worddb_data);
863 * Our data is the key creation time followed by the
866 worddb_data[ 0] = publickey->publickey->data[1];
867 worddb_data[ 1] = publickey->publickey->data[2];
868 worddb_data[ 2] = publickey->publickey->data[3];
869 worddb_data[ 3] = publickey->publickey->data[4];
870 worddb_data[ 4] = (keyid >> 56) & 0xFF;
871 worddb_data[ 5] = (keyid >> 48) & 0xFF;
872 worddb_data[ 6] = (keyid >> 40) & 0xFF;
873 worddb_data[ 7] = (keyid >> 32) & 0xFF;
874 worddb_data[ 8] = (keyid >> 24) & 0xFF;
875 worddb_data[ 9] = (keyid >> 16) & 0xFF;
876 worddb_data[10] = (keyid >> 8) & 0xFF;
877 worddb_data[11] = keyid & 0xFF;
879 ret = cursor->c_get(cursor,
885 ret = cursor->c_del(cursor, 0);
887 logthing(LOGTHING_ERROR,
888 "Problem deleting word: %s",
894 logthing(LOGTHING_ERROR,
895 "Problem deleting word: %s",
897 if (ret == DB_LOCK_DEADLOCK) {
902 ret = cursor->c_close(cursor);
906 * Free our UID and word lists.
908 llfree(wordlist, NULL);
909 for (i = 0; uids[i] != NULL; i++) {
915 free_publickey(publickey);
920 ret = id32db->cursor(id32db,
925 shortkeyid = keyid & 0xFFFFFFFF;
927 memset(&key, 0, sizeof(key));
928 memset(&data, 0, sizeof(data));
929 key.data = &shortkeyid;
930 key.size = sizeof(shortkeyid);
932 data.size = sizeof(keyid);
934 ret = cursor->c_get(cursor,
940 ret = cursor->c_del(cursor, 0);
942 logthing(LOGTHING_ERROR,
943 "Problem deleting short keyid: %s",
949 logthing(LOGTHING_ERROR,
950 "Problem deleting short keyid: %s",
952 if (ret == DB_LOCK_DEADLOCK) {
957 subkeyids = keysubkeys(publickey);
959 while (subkeyids != NULL && subkeyids[i] != 0) {
960 shortkeyid = subkeyids[i++] & 0xFFFFFFFF;
962 memset(&key, 0, sizeof(key));
963 memset(&data, 0, sizeof(data));
964 key.data = &shortkeyid;
965 key.size = sizeof(shortkeyid);
967 data.size = sizeof(keyid);
969 ret = cursor->c_get(cursor,
975 ret = cursor->c_del(cursor, 0);
977 logthing(LOGTHING_ERROR,
978 "Problem deleting short"
985 logthing(LOGTHING_ERROR,
986 "Problem deleting short keyid: %s",
988 if (ret == DB_LOCK_DEADLOCK) {
993 if (subkeyids != NULL) {
997 ret = cursor->c_close(cursor);
1003 get_skshash(publickey, &hash);
1005 memset(&key, 0, sizeof(key));
1006 memset(&data, 0, sizeof(data));
1007 key.data = hash.hash;
1008 key.size = sizeof(hash.hash);
1010 data.size = sizeof(keyid);
1012 ret = cursor->c_get(cursor,
1018 ret = cursor->c_del(cursor, 0);
1022 logthing(LOGTHING_ERROR,
1023 "Problem deleting skshash: %s",
1025 if (ret == DB_LOCK_DEADLOCK) {
1030 ret = cursor->c_close(cursor);
1036 key.size = sizeof(keyid);
1038 keydb(keyid)->del(keydb(keyid),
1048 return deadlock ? (-1) : (ret == DB_NOTFOUND);
1052 * store_key - Takes a key and stores it.
1053 * @publickey: A pointer to the public key to store.
1054 * @intrans: If we're already in a transaction.
1055 * @update: If true the key exists and should be updated.
1057 * Again we just use the hex representation of the keyid as the filename
1058 * to store the key to. We flatten the public key to a list of OpenPGP
1059 * packets and then use write_openpgp_stream() to write the stream out to
1060 * the file. If update is true then we delete the old key first, otherwise
1061 * we trust that it doesn't exist.
1063 static int db4_store_key(struct openpgp_publickey *publickey, bool intrans,
1066 struct openpgp_packet_list *packets = NULL;
1067 struct openpgp_packet_list *list_end = NULL;
1068 struct openpgp_publickey *next = NULL;
1071 struct buffer_ctx storebuf;
1075 uint32_t shortkeyid = 0;
1076 uint64_t *subkeyids = NULL;
1078 char *primary = NULL;
1079 unsigned char worddb_data[12];
1080 struct ll *wordlist = NULL;
1081 struct ll *curword = NULL;
1082 bool deadlock = false;
1083 struct skshash hash;
1085 keyid = get_keyid(publickey);
1092 * Delete the key if we already have it.
1094 * TODO: Can we optimize this perhaps? Possibly when other data is
1095 * involved as well? I suspect this is easiest and doesn't make a lot
1096 * of difference though - the largest chunk of data is the keydata and
1097 * it definitely needs updated.
1100 deadlock = (db4_delete_key(keyid, true) == -1);
1104 * Convert the key to a flat set of binary data.
1107 next = publickey->next;
1108 publickey->next = NULL;
1109 flatten_publickey(publickey, &packets, &list_end);
1110 publickey->next = next;
1112 storebuf.offset = 0;
1113 storebuf.size = 8192;
1114 storebuf.buffer = malloc(8192);
1116 write_openpgp_stream(buffer_putchar, &storebuf, packets);
1119 * Now we have the key data store it in the DB; the keyid is
1122 memset(&key, 0, sizeof(key));
1123 memset(&data, 0, sizeof(data));
1125 key.size = sizeof(keyid);
1126 data.size = storebuf.offset;
1127 data.data = storebuf.buffer;
1129 ret = keydb(keyid)->put(keydb(keyid),
1135 logthing(LOGTHING_ERROR,
1136 "Problem storing key: %s",
1138 if (ret == DB_LOCK_DEADLOCK) {
1143 free(storebuf.buffer);
1144 storebuf.buffer = NULL;
1146 storebuf.offset = 0;
1148 free_packet_list(packets);
1153 * Walk through our uids storing the words into the db with the keyid.
1156 uids = keyuids(publickey, &primary);
1159 for (i = 0; ret == 0 && uids[i] != NULL; i++) {
1160 wordlist = makewordlist(wordlist, uids[i]);
1163 for (curword = wordlist; curword != NULL && !deadlock;
1164 curword = curword->next) {
1165 memset(&key, 0, sizeof(key));
1166 memset(&data, 0, sizeof(data));
1167 key.data = curword->object;
1168 key.size = strlen(key.data);
1169 data.data = worddb_data;
1170 data.size = sizeof(worddb_data);
1173 * Our data is the key creation time followed by the
1176 worddb_data[ 0] = publickey->publickey->data[1];
1177 worddb_data[ 1] = publickey->publickey->data[2];
1178 worddb_data[ 2] = publickey->publickey->data[3];
1179 worddb_data[ 3] = publickey->publickey->data[4];
1180 worddb_data[ 4] = (keyid >> 56) & 0xFF;
1181 worddb_data[ 5] = (keyid >> 48) & 0xFF;
1182 worddb_data[ 6] = (keyid >> 40) & 0xFF;
1183 worddb_data[ 7] = (keyid >> 32) & 0xFF;
1184 worddb_data[ 8] = (keyid >> 24) & 0xFF;
1185 worddb_data[ 9] = (keyid >> 16) & 0xFF;
1186 worddb_data[10] = (keyid >> 8) & 0xFF;
1187 worddb_data[11] = keyid & 0xFF;
1188 ret = worddb->put(worddb,
1194 logthing(LOGTHING_ERROR,
1195 "Problem storing word: %s",
1197 if (ret == DB_LOCK_DEADLOCK) {
1204 * Free our UID and word lists.
1206 llfree(wordlist, NULL);
1207 for (i = 0; uids[i] != NULL; i++) {
1216 * Write the truncated 32 bit keyid so we can lookup the full id for
1220 shortkeyid = keyid & 0xFFFFFFFF;
1222 memset(&key, 0, sizeof(key));
1223 memset(&data, 0, sizeof(data));
1224 key.data = &shortkeyid;
1225 key.size = sizeof(shortkeyid);
1227 data.size = sizeof(keyid);
1229 ret = id32db->put(id32db,
1235 logthing(LOGTHING_ERROR,
1236 "Problem storing short keyid: %s",
1238 if (ret == DB_LOCK_DEADLOCK) {
1245 subkeyids = keysubkeys(publickey);
1247 while (subkeyids != NULL && subkeyids[i] != 0) {
1248 shortkeyid = subkeyids[i++] & 0xFFFFFFFF;
1250 memset(&key, 0, sizeof(key));
1251 memset(&data, 0, sizeof(data));
1252 key.data = &shortkeyid;
1253 key.size = sizeof(shortkeyid);
1255 data.size = sizeof(keyid);
1257 ret = id32db->put(id32db,
1263 logthing(LOGTHING_ERROR,
1264 "Problem storing short keyid: %s",
1266 if (ret == DB_LOCK_DEADLOCK) {
1271 if (subkeyids != NULL) {
1278 get_skshash(publickey, &hash);
1279 memset(&key, 0, sizeof(key));
1280 memset(&data, 0, sizeof(data));
1281 key.data = hash.hash;
1282 key.size = sizeof(hash.hash);
1284 data.size = sizeof(keyid);
1286 ret = skshashdb->put(skshashdb,
1292 logthing(LOGTHING_ERROR,
1293 "Problem storing SKS hash: %s",
1295 if (ret == DB_LOCK_DEADLOCK) {
1305 return deadlock ? -1 : 0 ;
1309 * iterate_keys - call a function once for each key in the db.
1310 * @iterfunc: The function to call.
1311 * @ctx: A context pointer
1313 * Calls iterfunc once for each key in the database. ctx is passed
1314 * unaltered to iterfunc. This function is intended to aid database dumps
1315 * and statistic calculations.
1317 * Returns the number of keys we iterated over.
1319 static int db4_iterate_keys(void (*iterfunc)(void *ctx,
1320 struct openpgp_publickey *key), void *ctx)
1327 struct buffer_ctx fetchbuf;
1328 struct openpgp_packet_list *packets = NULL;
1329 struct openpgp_publickey *key = NULL;
1331 for (i = 0; i < numdbs; i++) {
1332 ret = dbconns[i]->cursor(dbconns[i],
1337 memset(&dbkey, 0, sizeof(dbkey));
1338 memset(&data, 0, sizeof(data));
1339 ret = cursor->c_get(cursor, &dbkey, &data, DB_NEXT);
1341 fetchbuf.buffer = data.data;
1342 fetchbuf.offset = 0;
1343 fetchbuf.size = data.size;
1344 read_openpgp_stream(buffer_fetchchar, &fetchbuf,
1346 parse_keys(packets, &key);
1350 free_publickey(key);
1352 free_packet_list(packets);
1355 memset(&dbkey, 0, sizeof(dbkey));
1356 memset(&data, 0, sizeof(data));
1357 ret = cursor->c_get(cursor, &dbkey, &data,
1361 if (ret != DB_NOTFOUND) {
1362 logthing(LOGTHING_ERROR,
1363 "Problem reading key: %s",
1367 ret = cursor->c_close(cursor);
1375 * Include the basic keydb routines.
1377 #define NEED_GETKEYSIGS 1
1378 #define NEED_KEYID2UID 1
1379 #define NEED_UPDATEKEYS 1
1382 struct dbfuncs keydb_db4_funcs = {
1383 .initdb = db4_initdb,
1384 .cleanupdb = db4_cleanupdb,
1385 .starttrans = db4_starttrans,
1386 .endtrans = db4_endtrans,
1387 .fetch_key = db4_fetch_key,
1388 .fetch_key_text = db4_fetch_key_text,
1389 .fetch_key_skshash = db4_fetch_key_skshash,
1390 .store_key = db4_store_key,
1391 .update_keys = generic_update_keys,
1392 .delete_key = db4_delete_key,
1393 .getkeysigs = generic_getkeysigs,
1394 .cached_getkeysigs = generic_cached_getkeysigs,
1395 .keyid2uid = generic_keyid2uid,
1396 .getfullkeyid = db4_getfullkeyid,
1397 .iterate_keys = db4_iterate_keys,