X-Git-Url: https://the.earth.li/gitweb/?a=blobdiff_plain;f=keydb_db4.c;h=f3d20dbcafd3ff8521981b455a05c110418f8dec;hb=adc800dbc424a1e246dd4a82a0c2e88eeda25531;hp=6a21fab73678a811a286eeff35a6d3d7e97f2351;hpb=83ae316a7b14e55418349e87d1a1942a0627ae14;p=onak.git diff --git a/keydb_db4.c b/keydb_db4.c index 6a21fab..f3d20db 100644 --- a/keydb_db4.c +++ b/keydb_db4.c @@ -13,8 +13,7 @@ * more details. * * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 51 - * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * this program. If not, see . */ #include @@ -23,6 +22,8 @@ #include #include #include +#include +#include #include #include #include @@ -37,7 +38,9 @@ #include "decodekey.h" #include "keystructs.h" #include "mem.h" +#include "ll.h" #include "log.h" +#include "onak.h" #include "onak-conf.h" #include "parsekey.h" #include "wordlist.h" @@ -50,12 +53,13 @@ struct onak_db4_dbctx { DB **dbconns; /* Connections to the key data databases */ DB *worddb; /* Connection to the word lookup database */ DB *id32db; /* Connection to the 32 bit ID lookup database */ + DB *id64db; /* Connection to the 64 bit ID lookup database */ DB *skshashdb; /* Connection to the SKS hash database */ DB *subkeydb; /* Connection to the subkey ID lookup database */ DB_TXN *txn; /* Our current transaction ID */ }; -DB *keydb(struct onak_db4_dbctx *privctx, uint64_t keyid) +DB *keydb_id(struct onak_db4_dbctx *privctx, uint64_t keyid) { uint64_t keytrun; @@ -64,6 +68,18 @@ DB *keydb(struct onak_db4_dbctx *privctx, uint64_t keyid) return(privctx->dbconns[keytrun % privctx->numdbs]); } +DB *keydb_fp(struct onak_db4_dbctx *privctx, struct openpgp_fingerprint *fp) +{ + uint64_t keytrun; + + keytrun = (fp->fp[4] << 24) | + (fp->fp[5] << 16) | + (fp->fp[6] << 8) | + (fp->fp[7]); + + return(privctx->dbconns[keytrun % privctx->numdbs]); +} + /** * db4_errfunc - Direct DB errors to logfile * @@ -148,16 +164,18 @@ static void db4_endtrans(struct onak_dbctx *dbctx) * we're running with a newer version of db4 than the database was * created with. */ -static int db4_upgradedb(struct onak_db4_dbctx *privctx) +static int db4_upgradedb(struct onak_dbctx *dbctx) { + struct onak_db4_dbctx *privctx = (struct onak_db4_dbctx *) dbctx->priv; DB *curdb = NULL; int ret; int i; char buf[1024]; int lockfile_fd; struct stat statbuf; + ssize_t written; - snprintf(buf, sizeof(buf) - 1, "%s/%s", config.db_dir, + snprintf(buf, sizeof(buf) - 1, "%s/%s", dbctx->config->location, DB4_UPGRADE_FILE); lockfile_fd = open(buf, O_RDWR | O_CREAT | O_EXCL, 0600); if (lockfile_fd < 0) { @@ -171,21 +189,29 @@ static int db4_upgradedb(struct onak_db4_dbctx *privctx) } } snprintf(buf, sizeof(buf) - 1, "%d", getpid()); - write(lockfile_fd, buf, strlen(buf)); + written = write(lockfile_fd, buf, strlen(buf)); close(lockfile_fd); + if (written != strlen(buf)) { + logthing(LOGTHING_CRITICAL, "Couldn't write PID to lockfile: " + "%s", strerror(errno)); + snprintf(buf, sizeof(buf) - 1, "%s/%s", dbctx->config->location, + DB4_UPGRADE_FILE); + unlink(buf); + return -1; + } logthing(LOGTHING_NOTICE, "Upgrading DB4 database"); ret = db_env_create(&privctx->dbenv, 0); if (ret == 0) { privctx->dbenv->set_errcall(privctx->dbenv, &db4_errfunc); - privctx->dbenv->remove(privctx->dbenv, config.db_dir, 0); + privctx->dbenv->remove(privctx->dbenv, dbctx->config->location, 0); privctx->dbenv = NULL; } for (i = 0; i < privctx->numdbs; i++) { ret = db_create(&curdb, NULL, 0); if (ret == 0) { snprintf(buf, sizeof(buf) - 1, "%s/keydb.%d.db", - config.db_dir, i); + dbctx->config->location, i); logthing(LOGTHING_DEBUG, "Upgrading %s", buf); curdb->upgrade(curdb, buf, 0); curdb->close(curdb, 0); @@ -198,7 +224,7 @@ static int db4_upgradedb(struct onak_db4_dbctx *privctx) ret = db_create(&curdb, NULL, 0); if (ret == 0) { - snprintf(buf, sizeof(buf) - 1, "%s/worddb", config.db_dir); + snprintf(buf, sizeof(buf) - 1, "%s/worddb", dbctx->config->location); logthing(LOGTHING_DEBUG, "Upgrading %s", buf); curdb->upgrade(curdb, buf, 0); curdb->close(curdb, 0); @@ -210,7 +236,7 @@ static int db4_upgradedb(struct onak_db4_dbctx *privctx) ret = db_create(&curdb, NULL, 0); if (ret == 0) { - snprintf(buf, sizeof(buf) - 1, "%s/id32db", config.db_dir); + snprintf(buf, sizeof(buf) - 1, "%s/id32db", dbctx->config->location); logthing(LOGTHING_DEBUG, "Upgrading %s", buf); curdb->upgrade(curdb, buf, 0); curdb->close(curdb, 0); @@ -222,7 +248,7 @@ static int db4_upgradedb(struct onak_db4_dbctx *privctx) ret = db_create(&curdb, NULL, 0); if (ret == 0) { - snprintf(buf, sizeof(buf) - 1, "%s/skshashdb", config.db_dir); + snprintf(buf, sizeof(buf) - 1, "%s/id64db", dbctx->config->location); logthing(LOGTHING_DEBUG, "Upgrading %s", buf); curdb->upgrade(curdb, buf, 0); curdb->close(curdb, 0); @@ -234,7 +260,7 @@ static int db4_upgradedb(struct onak_db4_dbctx *privctx) ret = db_create(&curdb, NULL, 0); if (ret == 0) { - snprintf(buf, sizeof(buf) - 1, "%s/subkeydb", config.db_dir); + snprintf(buf, sizeof(buf) - 1, "%s/skshashdb", dbctx->config->location); logthing(LOGTHING_DEBUG, "Upgrading %s", buf); curdb->upgrade(curdb, buf, 0); curdb->close(curdb, 0); @@ -244,7 +270,19 @@ static int db4_upgradedb(struct onak_db4_dbctx *privctx) db_strerror(ret)); } - snprintf(buf, sizeof(buf) - 1, "%s/%s", config.db_dir, + ret = db_create(&curdb, NULL, 0); + if (ret == 0) { + snprintf(buf, sizeof(buf) - 1, "%s/subkeydb", dbctx->config->location); + logthing(LOGTHING_DEBUG, "Upgrading %s", buf); + curdb->upgrade(curdb, buf, 0); + curdb->close(curdb, 0); + } else { + logthing(LOGTHING_ERROR, "Error upgrading DB %s : %s", + buf, + db_strerror(ret)); + } + + snprintf(buf, sizeof(buf) - 1, "%s/%s", dbctx->config->location, DB4_UPGRADE_FILE); unlink(buf); @@ -265,6 +303,7 @@ static uint64_t db4_getfullkeyid(struct onak_dbctx *dbctx, uint64_t keyid) DBC *cursor = NULL; uint32_t shortkeyid = 0; int ret = 0; + int i; if (keyid < 0x100000000LL) { ret = privctx->id32db->cursor(privctx->id32db, @@ -290,7 +329,15 @@ static uint64_t db4_getfullkeyid(struct onak_dbctx *dbctx, uint64_t keyid) DB_SET); if (ret == 0) { - keyid = *(uint64_t *) data.data; + if (data.size == 8) { + keyid = * (uint64_t *) data.data; + } else { + keyid = 0; + for (i = 12; i < 20; i++) { + keyid <<= 8; + keyid |= ((uint8_t *) data.data)[i]; + } + } if (data.data != NULL) { free(data.data); @@ -305,6 +352,100 @@ static uint64_t db4_getfullkeyid(struct onak_dbctx *dbctx, uint64_t keyid) return keyid; } +/** + * fetch_key_fp - Given a fingerprint fetch the key from storage. + */ +static int db4_fetch_key_fp(struct onak_dbctx *dbctx, + struct openpgp_fingerprint *fingerprint, + struct openpgp_publickey **publickey, + bool intrans) +{ + struct onak_db4_dbctx *privctx = (struct onak_db4_dbctx *) dbctx->priv; + struct openpgp_packet_list *packets = NULL; + DBT key, data; + int ret = 0; + int numkeys = 0; + struct buffer_ctx fetchbuf; + struct openpgp_fingerprint subfp; + + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + + data.size = 0; + data.data = NULL; + + key.size = fingerprint->length; + key.data = fingerprint->fp; + + if (!intrans) { + db4_starttrans(dbctx); + } + + ret = keydb_fp(privctx, fingerprint)->get(keydb_fp(privctx, + fingerprint), + privctx->txn, + &key, + &data, + 0); /* flags*/ + + if (ret == DB_NOTFOUND) { + /* If we didn't find the key ID see if it's a subkey ID */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + data.data = subfp.fp; + data.ulen = MAX_FINGERPRINT_LEN; + data.flags = DB_DBT_USERMEM; + key.data = fingerprint->fp; + key.size = fingerprint->length; + + ret = privctx->subkeydb->get(privctx->subkeydb, + privctx->txn, + &key, + &data, + 0); /* flags*/ + + if (ret == 0) { + /* We got a subkey match; retrieve the actual key */ + memset(&key, 0, sizeof(key)); + key.size = subfp.length = data.size; + key.data = subfp.fp; + + memset(&data, 0, sizeof(data)); + data.size = 0; + data.data = NULL; + + ret = keydb_fp(privctx, &subfp)->get( + keydb_fp(privctx, &subfp), + privctx->txn, + &key, + &data, + 0); /* flags*/ + } + } + + if (ret == 0) { + fetchbuf.buffer = data.data; + fetchbuf.offset = 0; + fetchbuf.size = data.size; + read_openpgp_stream(buffer_fetchchar, &fetchbuf, + &packets, 0); + parse_keys(packets, publickey); + free_packet_list(packets); + packets = NULL; + numkeys++; + } else if (ret != DB_NOTFOUND) { + logthing(LOGTHING_ERROR, + "Problem retrieving key: %s", + db_strerror(ret)); + } + + if (!intrans) { + db4_endtrans(dbctx); + } + + return (numkeys); +} + /** * fetch_key_id - Given a keyid fetch the key from storage. * @keyid: The keyid to fetch. @@ -327,6 +468,7 @@ static int db4_fetch_key_id(struct onak_dbctx *dbctx, uint64_t keyid, int ret = 0; int numkeys = 0; struct buffer_ctx fetchbuf; + struct openpgp_fingerprint fingerprint; if (keyid < 0x100000000LL) { keyid = db4_getfullkeyid(dbctx, keyid); @@ -345,39 +487,43 @@ static int db4_fetch_key_id(struct onak_dbctx *dbctx, uint64_t keyid, db4_starttrans(dbctx); } - ret = keydb(privctx, keyid)->get(keydb(privctx, keyid), + /* + * First we try a legacy stored key where we used the 64 bit key ID + * as the DB key. + */ + ret = keydb_id(privctx, keyid)->get(keydb_id(privctx, keyid), privctx->txn, &key, &data, 0); /* flags*/ if (ret == DB_NOTFOUND) { - /* If we didn't find the key ID see if it's a subkey ID */ + /* If we didn't find the key ID try the 64 bit map DB */ memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); - data.size = 0; - data.data = NULL; + data.ulen = MAX_FINGERPRINT_LEN; + data.data = fingerprint.fp; + data.flags = DB_DBT_USERMEM; key.size = sizeof(keyid); key.data = &keyid; - ret = privctx->subkeydb->get(privctx->subkeydb, + ret = privctx->id64db->get(privctx->id64db, privctx->txn, &key, &data, 0); /* flags*/ if (ret == 0) { - /* We got a subkey match; retrieve the actual key */ - keyid = *(uint64_t *) data.data; + /* We got a match; retrieve the actual key */ + fingerprint.length = data.size; memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); - data.size = 0; - data.data = NULL; - key.size = sizeof(keyid); - key.data = &keyid; + key.size = fingerprint.length; + key.data = fingerprint.fp; - ret = keydb(privctx, keyid)->get(keydb(privctx, keyid), + ret = keydb_fp(privctx, &fingerprint)->get( + keydb_fp(privctx, &fingerprint), privctx->txn, &key, &data, @@ -408,6 +554,7 @@ static int db4_fetch_key_id(struct onak_dbctx *dbctx, uint64_t keyid, return (numkeys); } + int worddb_cmp(const void *d1, const void *d2) { return memcmp(d1, d2, 12); @@ -437,6 +584,7 @@ static int db4_fetch_key_text(struct onak_dbctx *dbctx, const char *search, struct keyarray keylist = { NULL, 0, 0 }; struct keyarray newkeylist = { NULL, 0, 0 }; int firstpass = 1; + struct openpgp_fingerprint fingerprint; numkeys = 0; searchtext = strdup(search); @@ -467,11 +615,17 @@ static int db4_fetch_key_text(struct onak_dbctx *dbctx, const char *search, while (ret == 0 && strncmp(key.data, curword->object, key.size) == 0 && ((char *) curword->object)[key.size] == 0) { - keyid = 0; - for (i = 4; i < 12; i++) { - keyid <<= 8; - keyid += ((unsigned char *) - data.data)[i]; + if (data.size == 12) { + /* Old style creation + key id */ + fingerprint.length = 8; + for (i = 4; i < 12; i++) { + fingerprint.fp[i - 4] = + ((unsigned char *) + data.data)[i]; + } + } else { + fingerprint.length = data.size; + memcpy(fingerprint.fp, data.data, data.size); } /* @@ -479,8 +633,8 @@ static int db4_fetch_key_text(struct onak_dbctx *dbctx, const char *search, * our first pass (ie we have no existing key list), * or the key contained a previous word. */ - if (firstpass || array_find(&keylist, keyid)) { - array_add(&newkeylist, keyid); + if (firstpass || array_find(&keylist, &fingerprint)) { + array_add(&newkeylist, &fingerprint); } free(data.data); @@ -492,7 +646,9 @@ static int db4_fetch_key_text(struct onak_dbctx *dbctx, const char *search, DB_NEXT); } array_free(&keylist); - keylist = newkeylist; + keylist.keys = newkeylist.keys; + keylist.count = newkeylist.count; + keylist.size = newkeylist.size; newkeylist.keys = NULL; newkeylist.count = newkeylist.size = 0; if (data.data != NULL) { @@ -513,9 +669,20 @@ static int db4_fetch_key_text(struct onak_dbctx *dbctx, const char *search, db4_starttrans(dbctx); for (i = 0; i < keylist.count; i++) { - numkeys += db4_fetch_key_id(dbctx, keylist.keys[i], - publickey, - true); + if (keylist.keys[i].length == 8) { + keyid = 0; + for (int j = 0; j < 8; j++) { + keyid <<= 8; + keyid |= keylist.keys[i].fp[j]; + } + numkeys += db4_fetch_key_id(dbctx, keyid, + publickey, + true); + } else { + numkeys += db4_fetch_key_fp(dbctx, &keylist.keys[i], + publickey, + true); + } } array_free(&keylist); free(searchtext); @@ -534,7 +701,9 @@ static int db4_fetch_key_skshash(struct onak_dbctx *dbctx, DBT key, data; DBC *cursor = NULL; uint64_t keyid = 0; - int ret = 0; + int ret; + int count = 0; + struct openpgp_fingerprint fingerprint; ret = privctx->skshashdb->cursor(privctx->skshashdb, privctx->txn, @@ -557,7 +726,17 @@ static int db4_fetch_key_skshash(struct onak_dbctx *dbctx, DB_SET); if (ret == 0) { - keyid = *(uint64_t *) data.data; + if (data.size == 8) { + /* Legacy key ID record */ + keyid = *(uint64_t *) data.data; + count = db4_fetch_key_id(dbctx, keyid, publickey, + false); + } else { + fingerprint.length = data.size; + memcpy(fingerprint.fp, data.data, data.size); + count = db4_fetch_key_fp(dbctx, &fingerprint, + publickey, false); + } if (data.data != NULL) { free(data.data); @@ -568,7 +747,7 @@ static int db4_fetch_key_skshash(struct onak_dbctx *dbctx, cursor->c_close(cursor); cursor = NULL; - return db4_fetch_key_id(dbctx, keyid, publickey, false); + return count; } /** @@ -586,8 +765,10 @@ static int db4_delete_key(struct onak_dbctx *dbctx, struct openpgp_publickey *publickey = NULL; DBT key, data; DBC *cursor = NULL; - uint32_t shortkeyid = 0; - uint64_t *subkeyids = NULL; + DBC *cursor64 = NULL; + uint32_t shortkeyid = 0; + uint64_t subkeyid = 0; + struct openpgp_fingerprint *subkeyids = NULL; int ret = 0; int i; char **uids = NULL; @@ -597,12 +778,20 @@ static int db4_delete_key(struct onak_dbctx *dbctx, struct ll *curword = NULL; bool deadlock = false; struct skshash hash; + struct openpgp_fingerprint fingerprint; if (!intrans) { db4_starttrans(dbctx); } - db4_fetch_key_id(dbctx, keyid, &publickey, true); + if (db4_fetch_key_id(dbctx, keyid, &publickey, true) == 0) { + if (!intrans) { + db4_endtrans(dbctx); + } + return 1; + } + + get_fingerprint(publickey->publickey, &fingerprint); /* * Walk through the uids removing the words from the worddb. @@ -630,8 +819,8 @@ static int db4_delete_key(struct onak_dbctx *dbctx, data.size = sizeof(worddb_data); /* - * Our data is the key creation time followed by the - * key id. + * Old format word db data was the key creation time + * followed by the 64 bit key id. */ worddb_data[ 0] = publickey->publickey->data[1]; worddb_data[ 1] = publickey->publickey->data[2]; @@ -652,36 +841,16 @@ static int db4_delete_key(struct onak_dbctx *dbctx, DB_GET_BOTH); if (ret == 0) { - ret = cursor->c_del(cursor, 0); - } - - if (ret != 0) { - logthing(LOGTHING_ERROR, - "Problem deleting word: %s " - "(0x%016" PRIX64 ")", - db_strerror(ret), - keyid); - if (ret == DB_LOCK_DEADLOCK) { - deadlock = true; - } + cursor->c_del(cursor, 0); } - } - cursor->c_close(cursor); - cursor = NULL; - - ret = privctx->skshashdb->cursor(privctx->skshashdb, - privctx->txn, - &cursor, - 0); /* flags */ - if (ret == 0) { - get_skshash(publickey, &hash); + /* New style just uses the fingerprint as the data */ memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); - key.data = hash.hash; - key.size = sizeof(hash.hash); - data.data = &keyid; - data.size = sizeof(keyid); + key.data = curword->object; + key.size = strlen(key.data); + data.data = fingerprint.fp; + data.size = fingerprint.length; ret = cursor->c_get(cursor, &key, @@ -692,9 +861,9 @@ static int db4_delete_key(struct onak_dbctx *dbctx, ret = cursor->c_del(cursor, 0); } - if (ret != 0) { + if (ret != 0 && ret != DB_NOTFOUND) { logthing(LOGTHING_ERROR, - "Problem deleting skshash: %s " + "Problem deleting word: %s " "(0x%016" PRIX64 ")", db_strerror(ret), keyid); @@ -702,10 +871,9 @@ static int db4_delete_key(struct onak_dbctx *dbctx, deadlock = true; } } - - cursor->c_close(cursor); - cursor = NULL; } + cursor->c_close(cursor); + cursor = NULL; /* * Free our UID and word lists. @@ -717,8 +885,6 @@ static int db4_delete_key(struct onak_dbctx *dbctx, } free(uids); uids = NULL; - free_publickey(publickey); - publickey = NULL; } if (!deadlock) { @@ -726,9 +892,14 @@ static int db4_delete_key(struct onak_dbctx *dbctx, privctx->txn, &cursor, 0); /* flags */ + privctx->id64db->cursor(privctx->id64db, + privctx->txn, + &cursor64, + 0); /* flags */ shortkeyid = keyid & 0xFFFFFFFF; + /* Old style mapping to 64 bit key id */ memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); key.data = &shortkeyid; @@ -736,6 +907,23 @@ static int db4_delete_key(struct onak_dbctx *dbctx, data.data = &keyid; data.size = sizeof(keyid); + ret = cursor->c_get(cursor, + &key, + &data, + DB_GET_BOTH); + + if (ret == 0) { + cursor->c_del(cursor, 0); + } + + /* New style mapping to fingerprint */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = &shortkeyid; + key.size = sizeof(shortkeyid); + data.data = fingerprint.fp; + data.size = fingerprint.length; + ret = cursor->c_get(cursor, &key, &data, @@ -745,7 +933,7 @@ static int db4_delete_key(struct onak_dbctx *dbctx, ret = cursor->c_del(cursor, 0); } - if (ret != 0) { + if (ret != 0 && ret != DB_NOTFOUND) { logthing(LOGTHING_ERROR, "Problem deleting short keyid: %s " "(0x%016" PRIX64 ")", @@ -756,15 +944,44 @@ static int db4_delete_key(struct onak_dbctx *dbctx, } } + /* 64 bit key mapping to fingerprint */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = &keyid; + key.size = sizeof(keyid); + data.data = fingerprint.fp; + data.size = fingerprint.length; + + ret = cursor64->c_get(cursor64, + &key, + &data, + DB_GET_BOTH); + + if (ret == 0) { + ret = cursor64->c_del(cursor64, 0); + } + + if (ret != 0 && ret != DB_NOTFOUND) { + logthing(LOGTHING_ERROR, + "Problem deleting keyid: %s " + "(0x%016" PRIX64 ")", + db_strerror(ret), + keyid); + if (ret == DB_LOCK_DEADLOCK) { + deadlock = true; + } + } + subkeyids = keysubkeys(publickey); i = 0; - while (subkeyids != NULL && subkeyids[i] != 0) { + while (subkeyids != NULL && subkeyids[i].length != 0) { + subkeyid = fingerprint2keyid(&subkeyids[i]); memset(&key, 0, sizeof(key)); - key.data = &subkeyids[i]; - key.size = sizeof(subkeyids[i]); + key.data = subkeyids[i].fp; + key.size = subkeyids[i].length; privctx->subkeydb->del(privctx->subkeydb, privctx->txn, &key, 0); - if (ret != 0) { + if (ret != 0 && ret != DB_NOTFOUND) { logthing(LOGTHING_ERROR, "Problem deleting subkey id: %s " "(0x%016" PRIX64 ")", @@ -775,8 +992,9 @@ static int db4_delete_key(struct onak_dbctx *dbctx, } } - shortkeyid = subkeyids[i++] & 0xFFFFFFFF; + shortkeyid = subkeyid & 0xFFFFFFFF; + /* Remove 32 bit keyid -> 64 bit keyid mapping */ memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); key.data = &shortkeyid; @@ -784,6 +1002,23 @@ static int db4_delete_key(struct onak_dbctx *dbctx, data.data = &keyid; data.size = sizeof(keyid); + ret = cursor->c_get(cursor, + &key, + &data, + DB_GET_BOTH); + + if (ret == 0) { + cursor->c_del(cursor, 0); + } + + /* Remove 32 bit keyid -> fingerprint mapping */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = &shortkeyid; + key.size = sizeof(shortkeyid); + data.data = fingerprint.fp; + data.size = fingerprint.length; + ret = cursor->c_get(cursor, &key, &data, @@ -793,7 +1028,7 @@ static int db4_delete_key(struct onak_dbctx *dbctx, ret = cursor->c_del(cursor, 0); } - if (ret != 0) { + if (ret != 0 && ret != DB_NOTFOUND) { logthing(LOGTHING_ERROR, "Problem deleting short keyid: %s " "(0x%016" PRIX64 ")", @@ -803,20 +1038,121 @@ static int db4_delete_key(struct onak_dbctx *dbctx, deadlock = true; } } + + /* Remove 64 bit keyid -> fingerprint mapping */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = &subkeyid; + key.size = sizeof(subkeyid); + data.data = fingerprint.fp; + data.size = fingerprint.length; + + ret = cursor64->c_get(cursor64, + &key, + &data, + DB_GET_BOTH); + + if (ret == 0) { + ret = cursor64->c_del(cursor64, 0); + } + + if (ret != 0 && ret != DB_NOTFOUND) { + logthing(LOGTHING_ERROR, + "Problem deleting keyid: %s " + "(0x%016" PRIX64 ")", + db_strerror(ret), + keyid); + if (ret == DB_LOCK_DEADLOCK) { + deadlock = true; + } + } + i++; } if (subkeyids != NULL) { free(subkeyids); subkeyids = NULL; } + cursor64->c_close(cursor64); + cursor64 = NULL; cursor->c_close(cursor); cursor = NULL; } if (!deadlock) { + ret = privctx->skshashdb->cursor(privctx->skshashdb, + privctx->txn, + &cursor, + 0); /* flags */ + if (ret == 0) { + get_skshash(publickey, &hash); + + /* First delete old style keyid mapping */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = hash.hash; + key.size = sizeof(hash.hash); + data.data = &keyid; + data.size = sizeof(keyid); + + ret = cursor->c_get(cursor, + &key, + &data, + DB_GET_BOTH); + + if (ret == 0) { + cursor->c_del(cursor, 0); + } + + /* Then delete new style fingerprint mapping */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = hash.hash; + key.size = sizeof(hash.hash); + data.data = fingerprint.fp; + data.size = fingerprint.length; + + ret = cursor->c_get(cursor, + &key, + &data, + DB_GET_BOTH); + + if (ret == 0) { + ret = cursor->c_del(cursor, 0); + } + + if (ret != 0 && ret != DB_NOTFOUND) { + logthing(LOGTHING_ERROR, + "Problem deleting skshash: %s " + "(0x%016" PRIX64 ")", + db_strerror(ret), + keyid); + if (ret == DB_LOCK_DEADLOCK) { + deadlock = true; + } + } + + cursor->c_close(cursor); + cursor = NULL; + } + } + free_publickey(publickey); + publickey = NULL; + + if (!deadlock) { + key.data = fingerprint.fp; + key.size = fingerprint.length; + + keydb_fp(privctx, &fingerprint)->del(keydb_fp(privctx, + &fingerprint), + privctx->txn, + &key, + 0); /* flags */ + + /* Delete old style 64 bit keyid */ key.data = &keyid; key.size = sizeof(keyid); - keydb(privctx, keyid)->del(keydb(privctx, keyid), + keydb_id(privctx, keyid)->del(keydb_id(privctx, keyid), privctx->txn, &key, 0); /* flags */ @@ -856,20 +1192,25 @@ static int db4_store_key(struct onak_dbctx *dbctx, DBT data; uint64_t keyid = 0; uint32_t shortkeyid = 0; - uint64_t *subkeyids = NULL; + struct openpgp_fingerprint *subkeyids = NULL; char **uids = NULL; char *primary = NULL; - unsigned char worddb_data[12]; struct ll *wordlist = NULL; struct ll *curword = NULL; bool deadlock = false; struct skshash hash; + struct openpgp_fingerprint fingerprint; if (get_keyid(publickey, &keyid) != ONAK_E_OK) { logthing(LOGTHING_ERROR, "Couldn't find key ID for key."); return 0; } + if (get_fingerprint(publickey->publickey, &fingerprint) != ONAK_E_OK) { + logthing(LOGTHING_ERROR, "Couldn't find fingerprint for key."); + return 0; + } + if (!intrans) { db4_starttrans(dbctx); } @@ -907,12 +1248,13 @@ static int db4_store_key(struct onak_dbctx *dbctx, */ memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); - key.data = &keyid; - key.size = sizeof(keyid); + key.data = fingerprint.fp; + key.size = fingerprint.length; data.size = storebuf.offset; data.data = storebuf.buffer; - ret = keydb(privctx, keyid)->put(keydb(privctx, keyid), + ret = keydb_fp(privctx, &fingerprint)->put( + keydb_fp(privctx, &fingerprint), privctx->txn, &key, &data, @@ -952,25 +1294,9 @@ static int db4_store_key(struct onak_dbctx *dbctx, memset(&data, 0, sizeof(data)); key.data = curword->object; key.size = strlen(key.data); - data.data = worddb_data; - data.size = sizeof(worddb_data); + data.data = fingerprint.fp; + data.size = fingerprint.length; - /* - * Our data is the key creation time followed by the - * key id. - */ - worddb_data[ 0] = publickey->publickey->data[1]; - worddb_data[ 1] = publickey->publickey->data[2]; - worddb_data[ 2] = publickey->publickey->data[3]; - worddb_data[ 3] = publickey->publickey->data[4]; - worddb_data[ 4] = (keyid >> 56) & 0xFF; - worddb_data[ 5] = (keyid >> 48) & 0xFF; - worddb_data[ 6] = (keyid >> 40) & 0xFF; - worddb_data[ 7] = (keyid >> 32) & 0xFF; - worddb_data[ 8] = (keyid >> 24) & 0xFF; - worddb_data[ 9] = (keyid >> 16) & 0xFF; - worddb_data[10] = (keyid >> 8) & 0xFF; - worddb_data[11] = keyid & 0xFF; ret = privctx->worddb->put(privctx->worddb, privctx->txn, &key, @@ -999,8 +1325,8 @@ static int db4_store_key(struct onak_dbctx *dbctx, } /* - * Write the truncated 32 bit keyid so we can lookup the full id for - * queries. + * Write the truncated 32 bit keyid so we can lookup the fingerprint + * for queries. */ if (!deadlock) { shortkeyid = keyid & 0xFFFFFFFF; @@ -1009,8 +1335,8 @@ static int db4_store_key(struct onak_dbctx *dbctx, memset(&data, 0, sizeof(data)); key.data = &shortkeyid; key.size = sizeof(shortkeyid); - data.data = &keyid; - data.size = sizeof(keyid); + data.data = fingerprint.fp; + data.size = fingerprint.length; ret = privctx->id32db->put(privctx->id32db, privctx->txn, @@ -1027,17 +1353,44 @@ static int db4_store_key(struct onak_dbctx *dbctx, } } + /* + * Write the 64 bit keyid so we can lookup the fingerprint for + * queries. + */ + if (!deadlock) { + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = &keyid; + key.size = sizeof(keyid); + data.data = fingerprint.fp; + data.size = fingerprint.length; + + ret = privctx->id64db->put(privctx->id64db, + privctx->txn, + &key, + &data, + 0); + if (ret != 0) { + logthing(LOGTHING_ERROR, + "Problem storing keyid: %s", + db_strerror(ret)); + if (ret == DB_LOCK_DEADLOCK) { + deadlock = true; + } + } + } + if (!deadlock) { subkeyids = keysubkeys(publickey); i = 0; - while (subkeyids != NULL && subkeyids[i] != 0) { - /* Store the subkey ID -> main key ID mapping */ + while (subkeyids != NULL && subkeyids[i].length != 0) { + /* Store the subkey ID -> main key fp mapping */ memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); - key.data = &subkeyids[i]; - key.size = sizeof(subkeyids[i]); - data.data = &keyid; - data.size = sizeof(keyid); + key.data = subkeyids[i].fp; + key.size = subkeyids[i].length; + data.data = fingerprint.fp; + data.size = fingerprint.length; ret = privctx->subkeydb->put(privctx->subkeydb, privctx->txn, @@ -1053,15 +1406,39 @@ static int db4_store_key(struct onak_dbctx *dbctx, } } - /* Store the short subkey ID -> main key ID mapping */ - shortkeyid = subkeyids[i++] & 0xFFFFFFFF; + /* Store the 64 bit subkey ID -> main key fp mapping */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + + keyid = fingerprint2keyid(&subkeyids[i]); + key.data = &keyid; + key.size = sizeof(keyid); + data.data = fingerprint.fp; + data.size = fingerprint.length; + + ret = privctx->id64db->put(privctx->id64db, + privctx->txn, + &key, + &data, + 0); + if (ret != 0) { + logthing(LOGTHING_ERROR, + "Problem storing keyid: %s", + db_strerror(ret)); + if (ret == DB_LOCK_DEADLOCK) { + deadlock = true; + } + } + + /* Store the short subkey ID -> main key fp mapping */ + shortkeyid = keyid & 0xFFFFFFFF; memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); key.data = &shortkeyid; key.size = sizeof(shortkeyid); - data.data = &keyid; - data.size = sizeof(keyid); + data.data = fingerprint.fp; + data.size = fingerprint.length; ret = privctx->id32db->put(privctx->id32db, privctx->txn, @@ -1076,6 +1453,7 @@ static int db4_store_key(struct onak_dbctx *dbctx, deadlock = true; } } + i++; } if (subkeyids != NULL) { free(subkeyids); @@ -1089,8 +1467,8 @@ static int db4_store_key(struct onak_dbctx *dbctx, memset(&data, 0, sizeof(data)); key.data = hash.hash; key.size = sizeof(hash.hash); - data.data = &keyid; - data.size = sizeof(keyid); + data.data = fingerprint.fp; + data.size = fingerprint.length; ret = privctx->skshashdb->put(privctx->skshashdb, privctx->txn, @@ -1192,7 +1570,6 @@ static int db4_iterate_keys(struct onak_dbctx *dbctx, #define NEED_GETKEYSIGS 1 #define NEED_KEYID2UID 1 #define NEED_UPDATEKEYS 1 -#define NEED_GET_FP 1 #include "keydb.c" /** @@ -1216,6 +1593,10 @@ static void db4_cleanupdb(struct onak_dbctx *dbctx) privctx->skshashdb->close(privctx->skshashdb, 0); privctx->skshashdb = NULL; } + if (privctx->id64db != NULL) { + privctx->id64db->close(privctx->id64db, 0); + privctx->id64db = NULL; + } if (privctx->id32db != NULL) { privctx->id32db->close(privctx->id32db, 0); privctx->id32db = NULL; @@ -1249,7 +1630,7 @@ static void db4_cleanupdb(struct onak_dbctx *dbctx) * this file are called in order to allow the DB to be initialized ready * for access. */ -struct onak_dbctx *keydb_db4_init(bool readonly) +struct onak_dbctx *keydb_db4_init(struct onak_db_config *dbcfg, bool readonly) { char buf[1024]; FILE *numdb = NULL; @@ -1265,6 +1646,7 @@ struct onak_dbctx *keydb_db4_init(bool readonly) if (dbctx == NULL) { return NULL; } + dbctx->config = dbcfg; dbctx->priv = privctx = calloc(1, sizeof(*privctx)); if (privctx == NULL) { free(dbctx); @@ -1274,7 +1656,7 @@ struct onak_dbctx *keydb_db4_init(bool readonly) /* Default to 16 key data DBs */ privctx->numdbs = 16; - snprintf(buf, sizeof(buf) - 1, "%s/%s", config.db_dir, + snprintf(buf, sizeof(buf) - 1, "%s/%s", dbcfg->location, DB4_UPGRADE_FILE); ret = stat(buf, &statbuf); while ((ret == 0) || (errno != ENOENT)) { @@ -1289,7 +1671,7 @@ struct onak_dbctx *keydb_db4_init(bool readonly) } ret = 0; - snprintf(buf, sizeof(buf) - 1, "%s/num_keydb", config.db_dir); + snprintf(buf, sizeof(buf) - 1, "%s/num_keydb", dbcfg->location); numdb = fopen(buf, "r"); if (numdb != NULL) { if (fgets(buf, sizeof(buf), numdb) != NULL) { @@ -1329,12 +1711,14 @@ struct onak_dbctx *keydb_db4_init(bool readonly) * Up the number of locks we're allowed at once. We base this on * the maximum number of keys we're going to return. */ - maxlocks = config.maxkeys * 16; - if (maxlocks < 1000) { - maxlocks = 1000; + if (ret == 0) { + maxlocks = config.maxkeys * 16; + if (maxlocks < 1000) { + maxlocks = 1000; + } + privctx->dbenv->set_lk_max_locks(privctx->dbenv, maxlocks); + privctx->dbenv->set_lk_max_objects(privctx->dbenv, maxlocks); } - privctx->dbenv->set_lk_max_locks(privctx->dbenv, maxlocks); - privctx->dbenv->set_lk_max_objects(privctx->dbenv, maxlocks); /* * Enable deadlock detection so that we don't block indefinitely on @@ -1351,7 +1735,7 @@ struct onak_dbctx *keydb_db4_init(bool readonly) } if (ret == 0) { - ret = privctx->dbenv->open(privctx->dbenv, config.db_dir, + ret = privctx->dbenv->open(privctx->dbenv, dbcfg->location, DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_LOCK | DB_INIT_TXN | DB_CREATE, @@ -1360,7 +1744,7 @@ struct onak_dbctx *keydb_db4_init(bool readonly) if (ret == DB_VERSION_MISMATCH) { privctx->dbenv->close(privctx->dbenv, 0); privctx->dbenv = NULL; - ret = db4_upgradedb(privctx); + ret = db4_upgradedb(dbctx); if (ret == 0) { ret = db_env_create(&privctx->dbenv, 0); } @@ -1370,7 +1754,7 @@ struct onak_dbctx *keydb_db4_init(bool readonly) privctx->dbenv->set_lk_detect(privctx->dbenv, DB_LOCK_DEFAULT); ret = privctx->dbenv->open(privctx->dbenv, - config.db_dir, + dbcfg->location, DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_LOCK | DB_INIT_TXN | DB_CREATE | DB_RECOVER, @@ -1389,7 +1773,7 @@ struct onak_dbctx *keydb_db4_init(bool readonly) if (ret != 0) { logthing(LOGTHING_CRITICAL, "Error opening db environment: %s (%s)", - config.db_dir, + dbcfg->location, db_strerror(ret)); if (privctx->dbenv != NULL) { privctx->dbenv->close(privctx->dbenv, 0); @@ -1484,6 +1868,31 @@ struct onak_dbctx *keydb_db4_init(bool readonly) } } + if (ret == 0) { + ret = db_create(&privctx->id64db, privctx->dbenv, 0); + if (ret != 0) { + logthing(LOGTHING_CRITICAL, "db_create: %s", + db_strerror(ret)); + } + } + + if (ret == 0) { + ret = privctx->id64db->set_flags(privctx->id64db, DB_DUP); + } + + if (ret == 0) { + ret = privctx->id64db->open(privctx->id64db, privctx->txn, + "id64db", "id64db", DB_HASH, + flags, + 0664); + if (ret != 0) { + logthing(LOGTHING_CRITICAL, + "Error opening id64 database: %s (%s)", + "id64db", + db_strerror(ret)); + } + } + if (ret == 0) { ret = db_create(&privctx->skshashdb, privctx->dbenv, 0); if (ret != 0) { @@ -1543,7 +1952,7 @@ struct onak_dbctx *keydb_db4_init(bool readonly) dbctx->starttrans = db4_starttrans; dbctx->endtrans = db4_endtrans; dbctx->fetch_key_id = db4_fetch_key_id; - dbctx->fetch_key_fp = generic_fetch_key_fp; + dbctx->fetch_key_fp = db4_fetch_key_fp; dbctx->fetch_key_text = db4_fetch_key_text; dbctx->fetch_key_skshash = db4_fetch_key_skshash; dbctx->store_key = db4_store_key;