X-Git-Url: https://the.earth.li/gitweb/?a=blobdiff_plain;f=keydb_db4.c;h=1f306e267f60e9851c0dd65b0874517ba7afcb39;hb=dfab9e96ee1fa4a10acf9c1cf644d7a4366a5af6;hp=6a21fab73678a811a286eeff35a6d3d7e97f2351;hpb=83ae316a7b14e55418349e87d1a1942a0627ae14;p=onak.git diff --git a/keydb_db4.c b/keydb_db4.c index 6a21fab..1f306e2 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,21 @@ 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]; + keytrun <<= 8; + keytrun |= fp->fp[5]; + keytrun <<= 8; + keytrun |= fp->fp[6]; + keytrun <<= 8; + keytrun |= fp->fp[7]; + + return(privctx->dbconns[keytrun % privctx->numdbs]); +} + /** * db4_errfunc - Direct DB errors to logfile * @@ -148,16 +167,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 +192,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 +227,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 +239,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 +251,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 +263,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 +273,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); @@ -252,72 +293,10 @@ static int db4_upgradedb(struct onak_db4_dbctx *privctx) } /** - * getfullkeyid - Maps a 32bit key id to a 64bit one. - * @keyid: The 32bit keyid. - * - * This function maps a 32bit key id to the full 64bit one. It returns the - * full keyid. If the key isn't found a keyid of 0 is returned. - */ -static uint64_t db4_getfullkeyid(struct onak_dbctx *dbctx, uint64_t keyid) -{ - struct onak_db4_dbctx *privctx = (struct onak_db4_dbctx *) dbctx->priv; - DBT key, data; - DBC *cursor = NULL; - uint32_t shortkeyid = 0; - int ret = 0; - - if (keyid < 0x100000000LL) { - ret = privctx->id32db->cursor(privctx->id32db, - privctx->txn, - &cursor, - 0); /* flags */ - - if (ret != 0) { - return 0; - } - - shortkeyid = keyid & 0xFFFFFFFF; - - memset(&key, 0, sizeof(key)); - memset(&data, 0, sizeof(data)); - key.data = &shortkeyid; - key.size = sizeof(shortkeyid); - data.flags = DB_DBT_MALLOC; - - ret = cursor->c_get(cursor, - &key, - &data, - DB_SET); - - if (ret == 0) { - keyid = *(uint64_t *) data.data; - - if (data.data != NULL) { - free(data.data); - data.data = NULL; - } - } - - cursor->c_close(cursor); - cursor = NULL; - } - - return keyid; -} - -/** - * fetch_key_id - Given a keyid fetch the key from storage. - * @keyid: The keyid to fetch. - * @publickey: A pointer to a structure to return the key in. - * @intrans: If we're already in a transaction. - * - * We use the hex representation of the keyid as the filename to fetch the - * key from. The key is stored in the file as a binary OpenPGP stream of - * packets, so we can just use read_openpgp_stream() to read the packets - * in and then parse_keys() to parse the packets into a publickey - * structure. + * fetch_key_fp - Given a fingerprint fetch the key from storage. */ -static int db4_fetch_key_id(struct onak_dbctx *dbctx, uint64_t keyid, +static int db4_fetch_key_fp(struct onak_dbctx *dbctx, + struct openpgp_fingerprint *fingerprint, struct openpgp_publickey **publickey, bool intrans) { @@ -327,10 +306,7 @@ static int db4_fetch_key_id(struct onak_dbctx *dbctx, uint64_t keyid, int ret = 0; int numkeys = 0; struct buffer_ctx fetchbuf; - - if (keyid < 0x100000000LL) { - keyid = db4_getfullkeyid(dbctx, keyid); - } + struct openpgp_fingerprint subfp; memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); @@ -338,14 +314,15 @@ static int db4_fetch_key_id(struct onak_dbctx *dbctx, uint64_t keyid, data.size = 0; data.data = NULL; - key.size = sizeof(keyid); - key.data = &keyid; + key.size = fingerprint->length; + key.data = fingerprint->fp; if (!intrans) { db4_starttrans(dbctx); } - ret = keydb(privctx, keyid)->get(keydb(privctx, keyid), + ret = keydb_fp(privctx, fingerprint)->get(keydb_fp(privctx, + fingerprint), privctx->txn, &key, &data, @@ -355,10 +332,11 @@ static int db4_fetch_key_id(struct onak_dbctx *dbctx, uint64_t keyid, /* 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.size = 0; - data.data = NULL; - key.size = sizeof(keyid); - key.data = &keyid; + 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, @@ -368,16 +346,16 @@ static int db4_fetch_key_id(struct onak_dbctx *dbctx, uint64_t keyid, if (ret == 0) { /* We got a subkey match; retrieve the actual key */ - keyid = *(uint64_t *) data.data; - 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; - key.size = sizeof(keyid); - key.data = &keyid; - ret = keydb(privctx, keyid)->get(keydb(privctx, keyid), + ret = keydb_fp(privctx, &subfp)->get( + keydb_fp(privctx, &subfp), privctx->txn, &key, &data, @@ -408,9 +386,92 @@ static int db4_fetch_key_id(struct onak_dbctx *dbctx, uint64_t keyid, return (numkeys); } -int worddb_cmp(const void *d1, const void *d2) +/** + * fetch_key_id - Given a keyid fetch the key from storage. + * @keyid: The keyid to fetch. + * @publickey: A pointer to a structure to return the key in. + * @intrans: If we're already in a transaction. + * + * We use the hex representation of the keyid as the filename to fetch the + * key from. The key is stored in the file as a binary OpenPGP stream of + * packets, so we can just use read_openpgp_stream() to read the packets + * in and then parse_keys() to parse the packets into a publickey + * structure. + */ +static int db4_fetch_key_id(struct onak_dbctx *dbctx, uint64_t keyid, + struct openpgp_publickey **publickey, + bool intrans) { - return memcmp(d1, d2, 12); + struct onak_db4_dbctx *privctx = (struct onak_db4_dbctx *) dbctx->priv; + DBT key, data; + DBC *cursor = NULL; + int ret = 0; + int numkeys = 0; + uint32_t shortkeyid = 0; + struct openpgp_fingerprint fingerprint; + bool first; + + if (!intrans) { + db4_starttrans(dbctx); + } + + /* If the key ID fits in 32 bits assume it's a short key id */ + if (keyid < 0x100000000LL) { + ret = privctx->id32db->cursor(privctx->id32db, + privctx->txn, + &cursor, + 0); /* flags */ + + shortkeyid = keyid & 0xFFFFFFFF; + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = &shortkeyid; + key.size = sizeof(shortkeyid); + } else { + ret = privctx->id64db->cursor(privctx->id64db, + privctx->txn, + &cursor, + 0); /* flags*/ + + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = &keyid; + key.size = sizeof(keyid); + } + + if (ret != 0) { + return 0; + } + + memset(&data, 0, sizeof(data)); + data.ulen = MAX_FINGERPRINT_LEN; + data.data = fingerprint.fp; + data.flags = DB_DBT_USERMEM; + + first = true; + while (cursor->c_get(cursor, &key, &data, + first ? DB_SET : DB_NEXT_DUP) == 0) { + /* We got a match; retrieve the actual key */ + fingerprint.length = data.size; + + if (db4_fetch_key_fp(dbctx, &fingerprint, + publickey, true)) + numkeys++; + + memset(&data, 0, sizeof(data)); + data.ulen = MAX_FINGERPRINT_LEN; + data.data = fingerprint.fp; + data.flags = DB_DBT_USERMEM; + first = false; + } + cursor->c_close(cursor); + cursor = NULL; + + if (!intrans) { + db4_endtrans(dbctx); + } + + return (numkeys); } /** @@ -428,7 +489,6 @@ static int db4_fetch_key_text(struct onak_dbctx *dbctx, const char *search, DBC *cursor = NULL; DBT key, data; int ret; - uint64_t keyid; int i; int numkeys; char *searchtext = NULL; @@ -437,6 +497,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,20 +528,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]; - } + + fingerprint.length = data.size; + memcpy(fingerprint.fp, data.data, data.size); /* * Only add the keys containing this word if this is * 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 +550,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,7 +573,7 @@ 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], + numkeys += db4_fetch_key_fp(dbctx, &keylist.keys[i], publickey, true); } @@ -533,8 +593,9 @@ static int db4_fetch_key_skshash(struct onak_dbctx *dbctx, struct onak_db4_dbctx *privctx = (struct onak_db4_dbctx *) dbctx->priv; 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, @@ -549,7 +610,9 @@ static int db4_fetch_key_skshash(struct onak_dbctx *dbctx, memset(&data, 0, sizeof(data)); key.data = (void *) hash->hash; key.size = sizeof(hash->hash); - data.flags = DB_DBT_MALLOC; + data.ulen = MAX_FINGERPRINT_LEN; + data.data = fingerprint.fp; + data.flags = DB_DBT_USERMEM; ret = cursor->c_get(cursor, &key, @@ -557,52 +620,61 @@ static int db4_fetch_key_skshash(struct onak_dbctx *dbctx, DB_SET); if (ret == 0) { - keyid = *(uint64_t *) data.data; - - if (data.data != NULL) { - free(data.data); - data.data = NULL; - } + fingerprint.length = data.size; + count = db4_fetch_key_fp(dbctx, &fingerprint, + publickey, false); } cursor->c_close(cursor); cursor = NULL; - return db4_fetch_key_id(dbctx, keyid, publickey, false); + return count; } /** * delete_key - Given a keyid delete the key from storage. - * @keyid: The keyid to delete. + * @fp: The fingerprint of the key to delete. * @intrans: If we're already in a transaction. * * This function deletes a public key from whatever storage mechanism we * are using. Returns 0 if the key existed. */ static int db4_delete_key(struct onak_dbctx *dbctx, - uint64_t keyid, bool intrans) + struct openpgp_fingerprint *fp, + bool intrans) { struct onak_db4_dbctx *privctx = (struct onak_db4_dbctx *) dbctx->priv; 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; char *primary = NULL; - unsigned char worddb_data[12]; struct ll *wordlist = NULL; struct ll *curword = NULL; bool deadlock = false; struct skshash hash; + uint64_t keyid; if (!intrans) { db4_starttrans(dbctx); } - db4_fetch_key_id(dbctx, keyid, &publickey, true); + if (db4_fetch_key_fp(dbctx, fp, &publickey, true) == 0) { + if (!intrans) { + db4_endtrans(dbctx); + } + return 1; + } + + if (get_keyid(publickey, &keyid) != ONAK_E_OK) { + return 1; + } /* * Walk through the uids removing the words from the worddb. @@ -622,29 +694,16 @@ static int db4_delete_key(struct onak_dbctx *dbctx, for (curword = wordlist; curword != NULL && !deadlock; curword = curword->next) { + /* + * New style uses the fingerprint as the data + * Old (unsupported) style was the 64 bit keyid + */ memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); key.data = curword->object; key.size = strlen(key.data); - data.data = worddb_data; - data.size = sizeof(worddb_data); - - /* - * 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; + data.data = fp->fp; + data.size = fp->length; ret = cursor->c_get(cursor, &key, @@ -655,7 +714,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 word: %s " "(0x%016" PRIX64 ")", @@ -669,44 +728,6 @@ static int db4_delete_key(struct onak_dbctx *dbctx, cursor->c_close(cursor); cursor = NULL; - ret = privctx->skshashdb->cursor(privctx->skshashdb, - privctx->txn, - &cursor, - 0); /* flags */ - if (ret == 0) { - get_skshash(publickey, &hash); - - 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) { - ret = cursor->c_del(cursor, 0); - } - - if (ret != 0) { - 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 our UID and word lists. */ @@ -717,8 +738,6 @@ static int db4_delete_key(struct onak_dbctx *dbctx, } free(uids); uids = NULL; - free_publickey(publickey); - publickey = NULL; } if (!deadlock) { @@ -726,15 +745,20 @@ static int db4_delete_key(struct onak_dbctx *dbctx, privctx->txn, &cursor, 0); /* flags */ + privctx->id64db->cursor(privctx->id64db, + privctx->txn, + &cursor64, + 0); /* flags */ + /* 32 bit short key mapping to fingerprint */ 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 = fp->fp; + data.size = fp->length; ret = cursor->c_get(cursor, &key, @@ -745,7 +769,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 +780,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 = fp->fp; + data.size = fp->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]); - privctx->subkeydb->del(privctx->subkeydb, + key.data = subkeyids[i].fp; + key.size = subkeyids[i].length; + ret = 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,14 +828,15 @@ static int db4_delete_key(struct onak_dbctx *dbctx, } } - shortkeyid = subkeyids[i++] & 0xFFFFFFFF; + shortkeyid = subkeyid & 0xFFFFFFFF; + /* 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 = &keyid; - data.size = sizeof(keyid); + data.data = fp->fp; + data.size = fp->length; ret = cursor->c_get(cursor, &key, @@ -793,7 +847,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 +857,94 @@ 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 = fp->fp; + data.size = fp->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) { - key.data = &keyid; - key.size = sizeof(keyid); + ret = privctx->skshashdb->cursor(privctx->skshashdb, + privctx->txn, + &cursor, + 0); /* flags */ + if (ret == 0) { + get_skshash(publickey, &hash); + + /* Remove SKS hash -> fingerprint mapping */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = hash.hash; + key.size = sizeof(hash.hash); + data.data = fp->fp; + data.size = fp->length; + + ret = cursor->c_get(cursor, + &key, + &data, + DB_GET_BOTH); + + if (ret == 0) { + ret = cursor->c_del(cursor, 0); + } - keydb(privctx, keyid)->del(keydb(privctx, keyid), + 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 = fp->fp; + key.size = fp->length; + + keydb_fp(privctx, fp)->del(keydb_fp(privctx, fp), privctx->txn, &key, 0); /* flags */ @@ -856,20 +984,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); } @@ -883,7 +1016,7 @@ static int db4_store_key(struct onak_dbctx *dbctx, * it definitely needs updated. */ if (update) { - deadlock = (db4_delete_key(dbctx, keyid, true) == -1); + deadlock = (db4_delete_key(dbctx, &fingerprint, true) == -1); } /* @@ -902,17 +1035,18 @@ static int db4_store_key(struct onak_dbctx *dbctx, write_openpgp_stream(buffer_putchar, &storebuf, packets); /* - * Now we have the key data store it in the DB; the keyid is - * the key. + * Now we have the key data store it in the DB; the fingerprint + * is the key. */ 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, @@ -936,7 +1070,8 @@ static int db4_store_key(struct onak_dbctx *dbctx, } /* - * Walk through our uids storing the words into the db with the keyid. + * Walk through our uids storing the words into the db with the + * fingerprint. */ if (!deadlock) { uids = keyuids(publickey, &primary); @@ -952,25 +1087,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 +1118,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 +1128,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 +1146,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 +1199,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 +1246,7 @@ static int db4_store_key(struct onak_dbctx *dbctx, deadlock = true; } } + i++; } if (subkeyids != NULL) { free(subkeyids); @@ -1089,8 +1260,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 +1363,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 +1386,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 +1423,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 +1439,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 +1449,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 +1464,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 +1504,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 +1528,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 +1537,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 +1547,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 +1566,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 +1661,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 +1745,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; @@ -1552,7 +1754,6 @@ struct onak_dbctx *keydb_db4_init(bool readonly) dbctx->getkeysigs = generic_getkeysigs; dbctx->cached_getkeysigs = generic_cached_getkeysigs; dbctx->keyid2uid = generic_keyid2uid; - dbctx->getfullkeyid = db4_getfullkeyid; dbctx->iterate_keys = db4_iterate_keys; return dbctx;