2 * keydb_db4.c - Routines to store and fetch keys in a DB4 database.
4 * Copyright 2002-2008 Jonathan McDowell <noodles@earth.li>
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; version 2 of the License.
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License along with
16 * this program. If not, see <https://www.gnu.org/licenses/>.
19 #include <sys/types.h>
34 #include "charfuncs.h"
38 #include "decodekey.h"
39 #include "keystructs.h"
44 #include "onak-conf.h"
48 #define DB4_UPGRADE_FILE "db_upgrade.lck"
50 struct onak_db4_dbctx {
51 DB_ENV *dbenv; /* The database environment context */
52 int numdbs; /* Number of data databases in use */
53 DB **dbconns; /* Connections to the key data databases */
54 DB *worddb; /* Connection to the word lookup database */
55 DB *id32db; /* Connection to the 32 bit ID lookup database */
56 DB *id64db; /* Connection to the 64 bit ID lookup database */
57 DB *skshashdb; /* Connection to the SKS hash database */
58 DB *subkeydb; /* Connection to the subkey ID lookup database */
59 DB_TXN *txn; /* Our current transaction ID */
62 DB *keydb_id(struct onak_db4_dbctx *privctx, uint64_t keyid)
68 return(privctx->dbconns[keytrun % privctx->numdbs]);
71 DB *keydb_fp(struct onak_db4_dbctx *privctx, struct openpgp_fingerprint *fp)
83 return(privctx->dbconns[keytrun % privctx->numdbs]);
87 * db4_errfunc - Direct DB errors to logfile
89 * Basic function to take errors from the DB library and output them to
90 * the logfile rather than stderr.
92 #if (DB_VERSION_MAJOR == 4) && (DB_VERSION_MINOR < 3)
93 static void db4_errfunc(const char *errpfx, const char *errmsg)
95 static void db4_errfunc(const DB_ENV *edbenv, const char *errpfx,
100 logthing(LOGTHING_DEBUG, "db4 error: %s:%s", errpfx, errmsg);
102 logthing(LOGTHING_DEBUG, "db4 error: %s", errmsg);
109 * starttrans - Start a transaction.
111 * Start a transaction. Intended to be used if we're about to perform many
112 * operations on the database to help speed it all up, or if we want
113 * something to only succeed if all relevant operations are successful.
115 static bool db4_starttrans(struct onak_dbctx *dbctx)
117 struct onak_db4_dbctx *privctx = (struct onak_db4_dbctx *) dbctx->priv;
120 log_assert(privctx->dbenv != NULL);
121 log_assert(privctx->txn == NULL);
123 ret = privctx->dbenv->txn_begin(privctx->dbenv,
124 NULL, /* No parent transaction */
128 logthing(LOGTHING_CRITICAL,
129 "Error starting transaction: %s",
138 * endtrans - End a transaction.
140 * Ends a transaction.
142 static void db4_endtrans(struct onak_dbctx *dbctx)
144 struct onak_db4_dbctx *privctx = (struct onak_db4_dbctx *) dbctx->priv;
147 log_assert(privctx->dbenv != NULL);
148 log_assert(privctx->txn != NULL);
150 ret = privctx->txn->commit(privctx->txn,
153 logthing(LOGTHING_CRITICAL,
154 "Error ending transaction: %s",
164 * db4_upgradedb - Upgrade a DB4 database
166 * Called if we discover we need to upgrade our DB4 database; ie if
167 * we're running with a newer version of db4 than the database was
170 static int db4_upgradedb(struct onak_dbctx *dbctx)
172 struct onak_db4_dbctx *privctx = (struct onak_db4_dbctx *) dbctx->priv;
181 snprintf(buf, sizeof(buf) - 1, "%s/%s", dbctx->config->location,
183 lockfile_fd = open(buf, O_RDWR | O_CREAT | O_EXCL, 0600);
184 if (lockfile_fd < 0) {
185 if (errno == EEXIST) {
186 while (stat(buf, &statbuf) == 0) ;
189 logthing(LOGTHING_CRITICAL, "Couldn't open database "
190 "update lock file: %s", strerror(errno));
194 snprintf(buf, sizeof(buf) - 1, "%d", getpid());
195 written = write(lockfile_fd, buf, strlen(buf));
197 if (written != strlen(buf)) {
198 logthing(LOGTHING_CRITICAL, "Couldn't write PID to lockfile: "
199 "%s", strerror(errno));
200 snprintf(buf, sizeof(buf) - 1, "%s/%s", dbctx->config->location,
206 logthing(LOGTHING_NOTICE, "Upgrading DB4 database");
207 ret = db_env_create(&privctx->dbenv, 0);
209 privctx->dbenv->set_errcall(privctx->dbenv, &db4_errfunc);
210 privctx->dbenv->remove(privctx->dbenv, dbctx->config->location, 0);
211 privctx->dbenv = NULL;
213 for (i = 0; i < privctx->numdbs; i++) {
214 ret = db_create(&curdb, NULL, 0);
216 snprintf(buf, sizeof(buf) - 1, "%s/keydb.%d.db",
217 dbctx->config->location, i);
218 logthing(LOGTHING_DEBUG, "Upgrading %s", buf);
219 curdb->upgrade(curdb, buf, 0);
220 curdb->close(curdb, 0);
222 logthing(LOGTHING_ERROR, "Error upgrading DB %s : %s",
228 ret = db_create(&curdb, NULL, 0);
230 snprintf(buf, sizeof(buf) - 1, "%s/worddb", dbctx->config->location);
231 logthing(LOGTHING_DEBUG, "Upgrading %s", buf);
232 curdb->upgrade(curdb, buf, 0);
233 curdb->close(curdb, 0);
235 logthing(LOGTHING_ERROR, "Error upgrading DB %s : %s",
240 ret = db_create(&curdb, NULL, 0);
242 snprintf(buf, sizeof(buf) - 1, "%s/id32db", dbctx->config->location);
243 logthing(LOGTHING_DEBUG, "Upgrading %s", buf);
244 curdb->upgrade(curdb, buf, 0);
245 curdb->close(curdb, 0);
247 logthing(LOGTHING_ERROR, "Error upgrading DB %s : %s",
252 ret = db_create(&curdb, NULL, 0);
254 snprintf(buf, sizeof(buf) - 1, "%s/id64db", dbctx->config->location);
255 logthing(LOGTHING_DEBUG, "Upgrading %s", buf);
256 curdb->upgrade(curdb, buf, 0);
257 curdb->close(curdb, 0);
259 logthing(LOGTHING_ERROR, "Error upgrading DB %s : %s",
264 ret = db_create(&curdb, NULL, 0);
266 snprintf(buf, sizeof(buf) - 1, "%s/skshashdb", dbctx->config->location);
267 logthing(LOGTHING_DEBUG, "Upgrading %s", buf);
268 curdb->upgrade(curdb, buf, 0);
269 curdb->close(curdb, 0);
271 logthing(LOGTHING_ERROR, "Error upgrading DB %s : %s",
276 ret = db_create(&curdb, NULL, 0);
278 snprintf(buf, sizeof(buf) - 1, "%s/subkeydb", dbctx->config->location);
279 logthing(LOGTHING_DEBUG, "Upgrading %s", buf);
280 curdb->upgrade(curdb, buf, 0);
281 curdb->close(curdb, 0);
283 logthing(LOGTHING_ERROR, "Error upgrading DB %s : %s",
288 snprintf(buf, sizeof(buf) - 1, "%s/%s", dbctx->config->location,
296 * fetch_key_fp - Given a fingerprint fetch the key from storage.
298 static int db4_fetch_key_int(struct onak_dbctx *dbctx,
299 struct openpgp_fingerprint *fingerprint,
300 struct openpgp_publickey **publickey,
304 struct onak_db4_dbctx *privctx = (struct onak_db4_dbctx *) dbctx->priv;
305 struct openpgp_packet_list *packets = NULL;
309 struct buffer_ctx fetchbuf;
310 struct openpgp_fingerprint subfp;
312 memset(&key, 0, sizeof(key));
313 memset(&data, 0, sizeof(data));
318 key.size = fingerprint->length;
319 key.data = fingerprint->fp;
322 db4_starttrans(dbctx);
325 ret = keydb_fp(privctx, fingerprint)->get(keydb_fp(privctx,
332 if (ret == DB_NOTFOUND && dosubkey) {
333 /* If we didn't find the key ID see if it's a subkey ID */
334 memset(&key, 0, sizeof(key));
335 memset(&data, 0, sizeof(data));
336 data.data = subfp.fp;
337 data.ulen = MAX_FINGERPRINT_LEN;
338 data.flags = DB_DBT_USERMEM;
339 key.data = fingerprint->fp;
340 key.size = fingerprint->length;
342 ret = privctx->subkeydb->get(privctx->subkeydb,
349 /* We got a subkey match; retrieve the actual key */
350 memset(&key, 0, sizeof(key));
351 key.size = subfp.length = data.size;
354 memset(&data, 0, sizeof(data));
358 ret = keydb_fp(privctx, &subfp)->get(
359 keydb_fp(privctx, &subfp),
368 fetchbuf.buffer = data.data;
370 fetchbuf.size = data.size;
371 read_openpgp_stream(buffer_fetchchar, &fetchbuf,
373 parse_keys(packets, publickey);
374 free_packet_list(packets);
377 } else if (ret != DB_NOTFOUND) {
378 logthing(LOGTHING_ERROR,
379 "Problem retrieving key: %s",
390 static int db4_fetch_key(struct onak_dbctx *dbctx,
391 struct openpgp_fingerprint *fingerprint,
392 struct openpgp_publickey **publickey,
395 return db4_fetch_key_int(dbctx, fingerprint, publickey, intrans, false);
398 static int db4_fetch_key_fp(struct onak_dbctx *dbctx,
399 struct openpgp_fingerprint *fingerprint,
400 struct openpgp_publickey **publickey,
403 return db4_fetch_key_int(dbctx, fingerprint, publickey, intrans, true);
407 * fetch_key_id - Given a keyid fetch the key from storage.
408 * @keyid: The keyid to fetch.
409 * @publickey: A pointer to a structure to return the key in.
410 * @intrans: If we're already in a transaction.
412 * We use the hex representation of the keyid as the filename to fetch the
413 * key from. The key is stored in the file as a binary OpenPGP stream of
414 * packets, so we can just use read_openpgp_stream() to read the packets
415 * in and then parse_keys() to parse the packets into a publickey
418 static int db4_fetch_key_id(struct onak_dbctx *dbctx, uint64_t keyid,
419 struct openpgp_publickey **publickey,
422 struct onak_db4_dbctx *privctx = (struct onak_db4_dbctx *) dbctx->priv;
427 uint32_t shortkeyid = 0;
428 struct openpgp_fingerprint fingerprint;
432 db4_starttrans(dbctx);
435 /* If the key ID fits in 32 bits assume it's a short key id */
436 if (keyid < 0x100000000LL) {
437 ret = privctx->id32db->cursor(privctx->id32db,
442 shortkeyid = keyid & 0xFFFFFFFF;
443 memset(&key, 0, sizeof(key));
444 memset(&data, 0, sizeof(data));
445 key.data = &shortkeyid;
446 key.size = sizeof(shortkeyid);
448 ret = privctx->id64db->cursor(privctx->id64db,
453 memset(&key, 0, sizeof(key));
454 memset(&data, 0, sizeof(data));
456 key.size = sizeof(keyid);
463 memset(&data, 0, sizeof(data));
464 data.ulen = MAX_FINGERPRINT_LEN;
465 data.data = fingerprint.fp;
466 data.flags = DB_DBT_USERMEM;
469 while (cursor->c_get(cursor, &key, &data,
470 first ? DB_SET : DB_NEXT_DUP) == 0) {
471 /* We got a match; retrieve the actual key */
472 fingerprint.length = data.size;
474 if (db4_fetch_key_fp(dbctx, &fingerprint,
478 memset(&data, 0, sizeof(data));
479 data.ulen = MAX_FINGERPRINT_LEN;
480 data.data = fingerprint.fp;
481 data.flags = DB_DBT_USERMEM;
484 cursor->c_close(cursor);
495 * fetch_key_text - Trys to find the keys that contain the supplied text.
496 * @search: The text to search for.
497 * @publickey: A pointer to a structure to return the key in.
499 * This function searches for the supplied text and returns the keys that
502 static int db4_fetch_key_text(struct onak_dbctx *dbctx, const char *search,
503 struct openpgp_publickey **publickey)
505 struct onak_db4_dbctx *privctx = (struct onak_db4_dbctx *) dbctx->priv;
511 char *searchtext = NULL;
512 struct ll *wordlist = NULL;
513 struct ll *curword = NULL;
514 struct keyarray keylist = { NULL, 0, 0 };
515 struct keyarray newkeylist = { NULL, 0, 0 };
517 struct openpgp_fingerprint fingerprint;
520 searchtext = strdup(search);
521 wordlist = makewordlist(wordlist, searchtext);
523 for (curword = wordlist; curword != NULL; curword = curword->next) {
524 db4_starttrans(dbctx);
526 ret = privctx->worddb->cursor(privctx->worddb,
536 memset(&key, 0, sizeof(key));
537 memset(&data, 0, sizeof(data));
538 key.data = curword->object;
539 key.size = strlen(curword->object);
540 data.flags = DB_DBT_MALLOC;
541 ret = cursor->c_get(cursor,
545 while (ret == 0 && strncmp(key.data, curword->object,
547 ((char *) curword->object)[key.size] == 0) {
549 fingerprint.length = data.size;
550 memcpy(fingerprint.fp, data.data, data.size);
553 * Only add the keys containing this word if this is
554 * our first pass (ie we have no existing key list),
555 * or the key contained a previous word.
557 if (firstpass || array_find(&keylist, &fingerprint)) {
558 array_add(&newkeylist, &fingerprint);
564 ret = cursor->c_get(cursor,
569 array_free(&keylist);
570 keylist.keys = newkeylist.keys;
571 keylist.count = newkeylist.count;
572 keylist.size = newkeylist.size;
573 newkeylist.keys = NULL;
574 newkeylist.count = newkeylist.size = 0;
575 if (data.data != NULL) {
579 cursor->c_close(cursor);
584 llfree(wordlist, NULL);
587 if (keylist.count > config.maxkeys) {
588 keylist.count = config.maxkeys;
591 db4_starttrans(dbctx);
592 for (i = 0; i < keylist.count; i++) {
593 numkeys += db4_fetch_key_fp(dbctx, &keylist.keys[i],
597 array_free(&keylist);
606 static int db4_fetch_key_skshash(struct onak_dbctx *dbctx,
607 const struct skshash *hash,
608 struct openpgp_publickey **publickey)
610 struct onak_db4_dbctx *privctx = (struct onak_db4_dbctx *) dbctx->priv;
615 struct openpgp_fingerprint fingerprint;
617 ret = privctx->skshashdb->cursor(privctx->skshashdb,
626 memset(&key, 0, sizeof(key));
627 memset(&data, 0, sizeof(data));
628 key.data = (void *) hash->hash;
629 key.size = sizeof(hash->hash);
630 data.ulen = MAX_FINGERPRINT_LEN;
631 data.data = fingerprint.fp;
632 data.flags = DB_DBT_USERMEM;
634 ret = cursor->c_get(cursor,
640 fingerprint.length = data.size;
641 count = db4_fetch_key_fp(dbctx, &fingerprint,
645 cursor->c_close(cursor);
652 * delete_key - Given a keyid delete the key from storage.
653 * @fp: The fingerprint of the key to delete.
654 * @intrans: If we're already in a transaction.
656 * This function deletes a public key from whatever storage mechanism we
657 * are using. Returns 0 if the key existed.
659 static int db4_delete_key(struct onak_dbctx *dbctx,
660 struct openpgp_fingerprint *fp,
663 struct onak_db4_dbctx *privctx = (struct onak_db4_dbctx *) dbctx->priv;
664 struct openpgp_publickey *publickey = NULL;
667 DBC *cursor64 = NULL;
668 uint32_t shortkeyid = 0;
669 uint64_t subkeyid = 0;
670 struct openpgp_fingerprint *subkeyids = NULL;
674 char *primary = NULL;
675 struct ll *wordlist = NULL;
676 struct ll *curword = NULL;
677 bool deadlock = false;
682 db4_starttrans(dbctx);
685 if (db4_fetch_key_fp(dbctx, fp, &publickey, true) == 0) {
692 if (get_keyid(publickey, &keyid) != ONAK_E_OK) {
697 * Walk through the uids removing the words from the worddb.
699 if (publickey != NULL) {
700 uids = keyuids(publickey, &primary);
703 for (i = 0; ret == 0 && uids[i] != NULL; i++) {
704 wordlist = makewordlist(wordlist, uids[i]);
707 privctx->worddb->cursor(privctx->worddb,
712 for (curword = wordlist; curword != NULL && !deadlock;
713 curword = curword->next) {
715 * New style uses the fingerprint as the data
716 * Old (unsupported) style was the 64 bit keyid
718 memset(&key, 0, sizeof(key));
719 memset(&data, 0, sizeof(data));
720 key.data = curword->object;
721 key.size = strlen(key.data);
723 data.size = fp->length;
725 ret = cursor->c_get(cursor,
731 ret = cursor->c_del(cursor, 0);
734 if (ret != 0 && ret != DB_NOTFOUND) {
735 logthing(LOGTHING_ERROR,
736 "Problem deleting word: %s "
737 "(0x%016" PRIX64 ")",
740 if (ret == DB_LOCK_DEADLOCK) {
745 cursor->c_close(cursor);
749 * Free our UID and word lists.
751 llfree(wordlist, NULL);
752 for (i = 0; uids[i] != NULL; i++) {
761 privctx->id32db->cursor(privctx->id32db,
765 privctx->id64db->cursor(privctx->id64db,
770 /* 32 bit short key mapping to fingerprint */
771 shortkeyid = keyid & 0xFFFFFFFF;
773 memset(&key, 0, sizeof(key));
774 memset(&data, 0, sizeof(data));
775 key.data = &shortkeyid;
776 key.size = sizeof(shortkeyid);
778 data.size = fp->length;
780 ret = cursor->c_get(cursor,
786 ret = cursor->c_del(cursor, 0);
789 if (ret != 0 && ret != DB_NOTFOUND) {
790 logthing(LOGTHING_ERROR,
791 "Problem deleting short keyid: %s "
792 "(0x%016" PRIX64 ")",
795 if (ret == DB_LOCK_DEADLOCK) {
800 /* 64 bit key mapping to fingerprint */
801 memset(&key, 0, sizeof(key));
802 memset(&data, 0, sizeof(data));
804 key.size = sizeof(keyid);
806 data.size = fp->length;
808 ret = cursor64->c_get(cursor64,
814 ret = cursor64->c_del(cursor64, 0);
817 if (ret != 0 && ret != DB_NOTFOUND) {
818 logthing(LOGTHING_ERROR,
819 "Problem deleting keyid: %s "
820 "(0x%016" PRIX64 ")",
823 if (ret == DB_LOCK_DEADLOCK) {
828 subkeyids = keysubkeys(publickey);
830 while (subkeyids != NULL && subkeyids[i].length != 0) {
831 subkeyid = fingerprint2keyid(&subkeyids[i]);
832 memset(&key, 0, sizeof(key));
833 key.data = subkeyids[i].fp;
834 key.size = subkeyids[i].length;
835 ret = privctx->subkeydb->del(privctx->subkeydb,
836 privctx->txn, &key, 0);
837 if (ret != 0 && ret != DB_NOTFOUND) {
838 logthing(LOGTHING_ERROR,
839 "Problem deleting subkey id: %s "
840 "(0x%016" PRIX64 ")",
843 if (ret == DB_LOCK_DEADLOCK) {
848 shortkeyid = subkeyid & 0xFFFFFFFF;
850 /* Remove 32 bit keyid -> fingerprint mapping */
851 memset(&key, 0, sizeof(key));
852 memset(&data, 0, sizeof(data));
853 key.data = &shortkeyid;
854 key.size = sizeof(shortkeyid);
856 data.size = fp->length;
858 ret = cursor->c_get(cursor,
864 ret = cursor->c_del(cursor, 0);
867 if (ret != 0 && ret != DB_NOTFOUND) {
868 logthing(LOGTHING_ERROR,
869 "Problem deleting short keyid: %s "
870 "(0x%016" PRIX64 ")",
873 if (ret == DB_LOCK_DEADLOCK) {
878 /* Remove 64 bit keyid -> fingerprint mapping */
879 memset(&key, 0, sizeof(key));
880 memset(&data, 0, sizeof(data));
881 key.data = &subkeyid;
882 key.size = sizeof(subkeyid);
884 data.size = fp->length;
886 ret = cursor64->c_get(cursor64,
892 ret = cursor64->c_del(cursor64, 0);
895 if (ret != 0 && ret != DB_NOTFOUND) {
896 logthing(LOGTHING_ERROR,
897 "Problem deleting keyid: %s "
898 "(0x%016" PRIX64 ")",
901 if (ret == DB_LOCK_DEADLOCK) {
907 if (subkeyids != NULL) {
911 cursor64->c_close(cursor64);
913 cursor->c_close(cursor);
918 ret = privctx->skshashdb->cursor(privctx->skshashdb,
923 get_skshash(publickey, &hash);
925 /* Remove SKS hash -> fingerprint mapping */
926 memset(&key, 0, sizeof(key));
927 memset(&data, 0, sizeof(data));
928 key.data = hash.hash;
929 key.size = sizeof(hash.hash);
931 data.size = fp->length;
933 ret = cursor->c_get(cursor,
939 ret = cursor->c_del(cursor, 0);
942 if (ret != 0 && ret != DB_NOTFOUND) {
943 logthing(LOGTHING_ERROR,
944 "Problem deleting skshash: %s "
945 "(0x%016" PRIX64 ")",
948 if (ret == DB_LOCK_DEADLOCK) {
953 cursor->c_close(cursor);
957 free_publickey(publickey);
962 key.size = fp->length;
964 keydb_fp(privctx, fp)->del(keydb_fp(privctx, fp),
974 return deadlock ? (-1) : (ret == DB_NOTFOUND);
978 * store_key - Takes a key and stores it.
979 * @publickey: A pointer to the public key to store.
980 * @intrans: If we're already in a transaction.
981 * @update: If true the key exists and should be updated.
983 * Again we just use the hex representation of the keyid as the filename
984 * to store the key to. We flatten the public key to a list of OpenPGP
985 * packets and then use write_openpgp_stream() to write the stream out to
986 * the file. If update is true then we delete the old key first, otherwise
987 * we trust that it doesn't exist.
989 static int db4_store_key(struct onak_dbctx *dbctx,
990 struct openpgp_publickey *publickey, bool intrans,
993 struct onak_db4_dbctx *privctx = (struct onak_db4_dbctx *) dbctx->priv;
994 struct openpgp_packet_list *packets = NULL;
995 struct openpgp_packet_list *list_end = NULL;
996 struct openpgp_publickey *next = NULL;
999 struct buffer_ctx storebuf;
1003 uint32_t shortkeyid = 0;
1004 struct openpgp_fingerprint *subkeyids = NULL;
1006 char *primary = NULL;
1007 struct ll *wordlist = NULL;
1008 struct ll *curword = NULL;
1009 bool deadlock = false;
1010 struct skshash hash;
1011 struct openpgp_fingerprint fingerprint;
1013 if (get_keyid(publickey, &keyid) != ONAK_E_OK) {
1014 logthing(LOGTHING_ERROR, "Couldn't find key ID for key.");
1018 if (get_fingerprint(publickey->publickey, &fingerprint) != ONAK_E_OK) {
1019 logthing(LOGTHING_ERROR, "Couldn't find fingerprint for key.");
1024 db4_starttrans(dbctx);
1028 * Delete the key if we already have it.
1030 * TODO: Can we optimize this perhaps? Possibly when other data is
1031 * involved as well? I suspect this is easiest and doesn't make a lot
1032 * of difference though - the largest chunk of data is the keydata and
1033 * it definitely needs updated.
1036 deadlock = (db4_delete_key(dbctx, &fingerprint, true) == -1);
1040 * Convert the key to a flat set of binary data.
1043 next = publickey->next;
1044 publickey->next = NULL;
1045 flatten_publickey(publickey, &packets, &list_end);
1046 publickey->next = next;
1048 storebuf.offset = 0;
1049 storebuf.size = 8192;
1050 storebuf.buffer = malloc(8192);
1052 write_openpgp_stream(buffer_putchar, &storebuf, packets);
1055 * Now we have the key data store it in the DB; the fingerprint
1058 memset(&key, 0, sizeof(key));
1059 memset(&data, 0, sizeof(data));
1060 key.data = fingerprint.fp;
1061 key.size = fingerprint.length;
1062 data.size = storebuf.offset;
1063 data.data = storebuf.buffer;
1065 ret = keydb_fp(privctx, &fingerprint)->put(
1066 keydb_fp(privctx, &fingerprint),
1072 logthing(LOGTHING_ERROR,
1073 "Problem storing key: %s",
1075 if (ret == DB_LOCK_DEADLOCK) {
1080 free(storebuf.buffer);
1081 storebuf.buffer = NULL;
1083 storebuf.offset = 0;
1085 free_packet_list(packets);
1090 * Walk through our uids storing the words into the db with the
1094 uids = keyuids(publickey, &primary);
1097 for (i = 0; ret == 0 && uids[i] != NULL; i++) {
1098 wordlist = makewordlist(wordlist, uids[i]);
1101 for (curword = wordlist; curword != NULL && !deadlock;
1102 curword = curword->next) {
1103 memset(&key, 0, sizeof(key));
1104 memset(&data, 0, sizeof(data));
1105 key.data = curword->object;
1106 key.size = strlen(key.data);
1107 data.data = fingerprint.fp;
1108 data.size = fingerprint.length;
1110 ret = privctx->worddb->put(privctx->worddb,
1116 logthing(LOGTHING_ERROR,
1117 "Problem storing word: %s",
1119 if (ret == DB_LOCK_DEADLOCK) {
1126 * Free our UID and word lists.
1128 llfree(wordlist, NULL);
1129 for (i = 0; uids[i] != NULL; i++) {
1138 * Write the truncated 32 bit keyid so we can lookup the fingerprint
1142 shortkeyid = keyid & 0xFFFFFFFF;
1144 memset(&key, 0, sizeof(key));
1145 memset(&data, 0, sizeof(data));
1146 key.data = &shortkeyid;
1147 key.size = sizeof(shortkeyid);
1148 data.data = fingerprint.fp;
1149 data.size = fingerprint.length;
1151 ret = privctx->id32db->put(privctx->id32db,
1157 logthing(LOGTHING_ERROR,
1158 "Problem storing short keyid: %s",
1160 if (ret == DB_LOCK_DEADLOCK) {
1167 * Write the 64 bit keyid so we can lookup the fingerprint for
1171 memset(&key, 0, sizeof(key));
1172 memset(&data, 0, sizeof(data));
1174 key.size = sizeof(keyid);
1175 data.data = fingerprint.fp;
1176 data.size = fingerprint.length;
1178 ret = privctx->id64db->put(privctx->id64db,
1184 logthing(LOGTHING_ERROR,
1185 "Problem storing keyid: %s",
1187 if (ret == DB_LOCK_DEADLOCK) {
1194 subkeyids = keysubkeys(publickey);
1196 while (subkeyids != NULL && subkeyids[i].length != 0) {
1197 /* Store the subkey ID -> main key fp mapping */
1198 memset(&key, 0, sizeof(key));
1199 memset(&data, 0, sizeof(data));
1200 key.data = subkeyids[i].fp;
1201 key.size = subkeyids[i].length;
1202 data.data = fingerprint.fp;
1203 data.size = fingerprint.length;
1205 ret = privctx->subkeydb->put(privctx->subkeydb,
1211 logthing(LOGTHING_ERROR,
1212 "Problem storing subkey keyid: %s",
1214 if (ret == DB_LOCK_DEADLOCK) {
1219 /* Store the 64 bit subkey ID -> main key fp mapping */
1220 memset(&key, 0, sizeof(key));
1221 memset(&data, 0, sizeof(data));
1223 keyid = fingerprint2keyid(&subkeyids[i]);
1225 key.size = sizeof(keyid);
1226 data.data = fingerprint.fp;
1227 data.size = fingerprint.length;
1229 ret = privctx->id64db->put(privctx->id64db,
1235 logthing(LOGTHING_ERROR,
1236 "Problem storing keyid: %s",
1238 if (ret == DB_LOCK_DEADLOCK) {
1243 /* Store the short subkey ID -> main key fp mapping */
1244 shortkeyid = keyid & 0xFFFFFFFF;
1246 memset(&key, 0, sizeof(key));
1247 memset(&data, 0, sizeof(data));
1248 key.data = &shortkeyid;
1249 key.size = sizeof(shortkeyid);
1250 data.data = fingerprint.fp;
1251 data.size = fingerprint.length;
1253 ret = privctx->id32db->put(privctx->id32db,
1259 logthing(LOGTHING_ERROR,
1260 "Problem storing short keyid: %s",
1262 if (ret == DB_LOCK_DEADLOCK) {
1268 if (subkeyids != NULL) {
1275 get_skshash(publickey, &hash);
1276 memset(&key, 0, sizeof(key));
1277 memset(&data, 0, sizeof(data));
1278 key.data = hash.hash;
1279 key.size = sizeof(hash.hash);
1280 data.data = fingerprint.fp;
1281 data.size = fingerprint.length;
1283 ret = privctx->skshashdb->put(privctx->skshashdb,
1289 logthing(LOGTHING_ERROR,
1290 "Problem storing SKS hash: %s",
1292 if (ret == DB_LOCK_DEADLOCK) {
1299 db4_endtrans(dbctx);
1302 return deadlock ? -1 : 0 ;
1306 * iterate_keys - call a function once for each key in the db.
1307 * @iterfunc: The function to call.
1308 * @ctx: A context pointer
1310 * Calls iterfunc once for each key in the database. ctx is passed
1311 * unaltered to iterfunc. This function is intended to aid database dumps
1312 * and statistic calculations.
1314 * Returns the number of keys we iterated over.
1316 static int db4_iterate_keys(struct onak_dbctx *dbctx,
1317 void (*iterfunc)(void *ctx, struct openpgp_publickey *key),
1320 struct onak_db4_dbctx *privctx = (struct onak_db4_dbctx *) dbctx->priv;
1326 struct buffer_ctx fetchbuf;
1327 struct openpgp_packet_list *packets = NULL;
1328 struct openpgp_publickey *key = NULL;
1330 for (i = 0; i < privctx->numdbs; i++) {
1331 ret = privctx->dbconns[i]->cursor(privctx->dbconns[i],
1340 memset(&dbkey, 0, sizeof(dbkey));
1341 memset(&data, 0, sizeof(data));
1342 ret = cursor->c_get(cursor, &dbkey, &data, DB_NEXT);
1344 fetchbuf.buffer = data.data;
1345 fetchbuf.offset = 0;
1346 fetchbuf.size = data.size;
1347 read_openpgp_stream(buffer_fetchchar, &fetchbuf,
1349 parse_keys(packets, &key);
1353 free_publickey(key);
1355 free_packet_list(packets);
1358 memset(&dbkey, 0, sizeof(dbkey));
1359 memset(&data, 0, sizeof(data));
1360 ret = cursor->c_get(cursor, &dbkey, &data,
1364 if (ret != DB_NOTFOUND) {
1365 logthing(LOGTHING_ERROR,
1366 "Problem reading key: %s",
1370 cursor->c_close(cursor);
1378 * Include the basic keydb routines.
1380 #define NEED_GETKEYSIGS 1
1381 #define NEED_KEYID2UID 1
1382 #define NEED_UPDATEKEYS 1
1386 * cleanupdb - De-initialize the key database.
1388 * This function should be called upon program exit to allow the DB to
1389 * cleanup after itself.
1391 static void db4_cleanupdb(struct onak_dbctx *dbctx)
1393 struct onak_db4_dbctx *privctx = (struct onak_db4_dbctx *) dbctx->priv;
1396 if (privctx->dbenv != NULL) {
1397 privctx->dbenv->txn_checkpoint(privctx->dbenv, 0, 0, 0);
1398 if (privctx->subkeydb != NULL) {
1399 privctx->subkeydb->close(privctx->subkeydb, 0);
1400 privctx->subkeydb = NULL;
1402 if (privctx->skshashdb != NULL) {
1403 privctx->skshashdb->close(privctx->skshashdb, 0);
1404 privctx->skshashdb = NULL;
1406 if (privctx->id64db != NULL) {
1407 privctx->id64db->close(privctx->id64db, 0);
1408 privctx->id64db = NULL;
1410 if (privctx->id32db != NULL) {
1411 privctx->id32db->close(privctx->id32db, 0);
1412 privctx->id32db = NULL;
1414 if (privctx->worddb != NULL) {
1415 privctx->worddb->close(privctx->worddb, 0);
1416 privctx->worddb = NULL;
1418 for (i = 0; i < privctx->numdbs; i++) {
1419 if (privctx->dbconns[i] != NULL) {
1420 privctx->dbconns[i]->close(privctx->dbconns[i],
1422 privctx->dbconns[i] = NULL;
1425 free(privctx->dbconns);
1426 privctx->dbconns = NULL;
1427 privctx->dbenv->close(privctx->dbenv, 0);
1428 privctx->dbenv = NULL;
1437 * initdb - Initialize the key database.
1439 * This function should be called before any of the other functions in
1440 * this file are called in order to allow the DB to be initialized ready
1443 struct onak_dbctx *keydb_db4_init(struct onak_db_config *dbcfg, bool readonly)
1450 struct stat statbuf;
1452 struct onak_dbctx *dbctx;
1453 struct onak_db4_dbctx *privctx;
1455 dbctx = malloc(sizeof(*dbctx));
1456 if (dbctx == NULL) {
1459 dbctx->config = dbcfg;
1460 dbctx->priv = privctx = calloc(1, sizeof(*privctx));
1461 if (privctx == NULL) {
1466 /* Default to 16 key data DBs */
1467 privctx->numdbs = 16;
1469 snprintf(buf, sizeof(buf) - 1, "%s/%s", dbcfg->location,
1471 ret = stat(buf, &statbuf);
1472 while ((ret == 0) || (errno != ENOENT)) {
1474 logthing(LOGTHING_CRITICAL, "Couldn't stat upgrade "
1475 "lock file: %s (%d)", strerror(errno), ret);
1478 logthing(LOGTHING_DEBUG, "DB4 upgrade in progress; waiting.");
1480 ret = stat(buf, &statbuf);
1484 snprintf(buf, sizeof(buf) - 1, "%s/num_keydb", dbcfg->location);
1485 numdb = fopen(buf, "r");
1486 if (numdb != NULL) {
1487 if (fgets(buf, sizeof(buf), numdb) != NULL) {
1488 privctx->numdbs = atoi(buf);
1491 } else if (!readonly) {
1492 logthing(LOGTHING_ERROR, "Couldn't open num_keydb: %s",
1494 numdb = fopen(buf, "w");
1495 if (numdb != NULL) {
1496 fprintf(numdb, "%d", privctx->numdbs);
1499 logthing(LOGTHING_ERROR,
1500 "Couldn't write num_keydb: %s",
1505 privctx->dbconns = calloc(privctx->numdbs, sizeof (DB *));
1506 if (privctx->dbconns == NULL) {
1507 logthing(LOGTHING_CRITICAL,
1508 "Couldn't allocate memory for dbconns");
1513 ret = db_env_create(&privctx->dbenv, 0);
1515 logthing(LOGTHING_CRITICAL,
1516 "db_env_create: %s", db_strerror(ret));
1521 * Up the number of locks we're allowed at once. We base this on
1522 * the maximum number of keys we're going to return.
1525 maxlocks = config.maxkeys * 16;
1526 if (maxlocks < 1000) {
1529 privctx->dbenv->set_lk_max_locks(privctx->dbenv, maxlocks);
1530 privctx->dbenv->set_lk_max_objects(privctx->dbenv, maxlocks);
1534 * Enable deadlock detection so that we don't block indefinitely on
1535 * anything. What we really want is simple 2 state locks, but I'm not
1536 * sure how to make the standard DB functions do that yet.
1539 privctx->dbenv->set_errcall(privctx->dbenv, &db4_errfunc);
1540 ret = privctx->dbenv->set_lk_detect(privctx->dbenv, DB_LOCK_DEFAULT);
1542 logthing(LOGTHING_CRITICAL,
1543 "db_env_create: %s", db_strerror(ret));
1548 ret = privctx->dbenv->open(privctx->dbenv, dbcfg->location,
1549 DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_LOCK |
1553 #ifdef DB_VERSION_MISMATCH
1554 if (ret == DB_VERSION_MISMATCH) {
1555 privctx->dbenv->close(privctx->dbenv, 0);
1556 privctx->dbenv = NULL;
1557 ret = db4_upgradedb(dbctx);
1559 ret = db_env_create(&privctx->dbenv, 0);
1562 privctx->dbenv->set_errcall(privctx->dbenv,
1564 privctx->dbenv->set_lk_detect(privctx->dbenv,
1566 ret = privctx->dbenv->open(privctx->dbenv,
1568 DB_INIT_LOG | DB_INIT_MPOOL |
1569 DB_INIT_LOCK | DB_INIT_TXN |
1570 DB_CREATE | DB_RECOVER,
1574 privctx->dbenv->txn_checkpoint(
1584 logthing(LOGTHING_CRITICAL,
1585 "Error opening db environment: %s (%s)",
1588 if (privctx->dbenv != NULL) {
1589 privctx->dbenv->close(privctx->dbenv, 0);
1590 privctx->dbenv = NULL;
1596 db4_starttrans(dbctx);
1598 for (i = 0; !ret && i < privctx->numdbs; i++) {
1599 ret = db_create(&privctx->dbconns[i],
1602 logthing(LOGTHING_CRITICAL,
1603 "db_create: %s", db_strerror(ret));
1607 snprintf(buf, 1023, "keydb.%d.db", i);
1612 ret = privctx->dbconns[i]->open(
1613 privctx->dbconns[i],
1621 logthing(LOGTHING_CRITICAL,
1622 "Error opening key database:"
1632 ret = db_create(&privctx->worddb, privctx->dbenv, 0);
1634 logthing(LOGTHING_CRITICAL, "db_create: %s",
1640 ret = privctx->worddb->set_flags(privctx->worddb, DB_DUP);
1644 ret = privctx->worddb->open(privctx->worddb, privctx->txn,
1645 "worddb", "worddb", DB_BTREE,
1649 logthing(LOGTHING_CRITICAL,
1650 "Error opening word database: %s (%s)",
1657 ret = db_create(&privctx->id32db, privctx->dbenv, 0);
1659 logthing(LOGTHING_CRITICAL, "db_create: %s",
1665 ret = privctx->id32db->set_flags(privctx->id32db, DB_DUP);
1669 ret = privctx->id32db->open(privctx->id32db, privctx->txn,
1670 "id32db", "id32db", DB_HASH,
1674 logthing(LOGTHING_CRITICAL,
1675 "Error opening id32 database: %s (%s)",
1682 ret = db_create(&privctx->id64db, privctx->dbenv, 0);
1684 logthing(LOGTHING_CRITICAL, "db_create: %s",
1690 ret = privctx->id64db->set_flags(privctx->id64db, DB_DUP);
1694 ret = privctx->id64db->open(privctx->id64db, privctx->txn,
1695 "id64db", "id64db", DB_HASH,
1699 logthing(LOGTHING_CRITICAL,
1700 "Error opening id64 database: %s (%s)",
1707 ret = db_create(&privctx->skshashdb, privctx->dbenv, 0);
1709 logthing(LOGTHING_CRITICAL, "db_create: %s",
1715 ret = privctx->skshashdb->open(privctx->skshashdb, privctx->txn,
1717 "skshashdb", DB_HASH,
1721 logthing(LOGTHING_CRITICAL,
1722 "Error opening skshash database: %s (%s)",
1729 ret = db_create(&privctx->subkeydb, privctx->dbenv, 0);
1731 logthing(LOGTHING_CRITICAL, "db_create: %s",
1737 ret = privctx->subkeydb->open(privctx->subkeydb, privctx->txn,
1738 "subkeydb", "subkeydb",
1743 logthing(LOGTHING_CRITICAL,
1744 "Error opening subkey database: %s (%s)",
1750 if (privctx->txn != NULL) {
1751 db4_endtrans(dbctx);
1755 db4_cleanupdb(dbctx);
1756 logthing(LOGTHING_CRITICAL,
1757 "Error opening database; exiting");
1761 dbctx->cleanupdb = db4_cleanupdb;
1762 dbctx->starttrans = db4_starttrans;
1763 dbctx->endtrans = db4_endtrans;
1764 dbctx->fetch_key = db4_fetch_key;
1765 dbctx->fetch_key_fp = db4_fetch_key_fp;
1766 dbctx->fetch_key_id = db4_fetch_key_id;
1767 dbctx->fetch_key_text = db4_fetch_key_text;
1768 dbctx->fetch_key_skshash = db4_fetch_key_skshash;
1769 dbctx->store_key = db4_store_key;
1770 dbctx->update_keys = generic_update_keys;
1771 dbctx->delete_key = db4_delete_key;
1772 dbctx->getkeysigs = generic_getkeysigs;
1773 dbctx->cached_getkeysigs = generic_cached_getkeysigs;
1774 dbctx->keyid2uid = generic_keyid2uid;
1775 dbctx->iterate_keys = db4_iterate_keys;