X-Git-Url: https://the.earth.li/gitweb/?a=blobdiff_plain;f=keydb_db4.c;h=1f306e267f60e9851c0dd65b0874517ba7afcb39;hb=dfab9e96ee1fa4a10acf9c1cf644d7a4366a5af6;hp=9d5dd9009fcf85f2e4e27e04983e598260b11b5c;hpb=8e0907be1d73011075a99a0c029c56664e12843e;p=onak.git diff --git a/keydb_db4.c b/keydb_db4.c index 9d5dd90..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,31 @@ 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); - privctx->dbenv->set_errcall(privctx->dbenv, &db4_errfunc); - privctx->dbenv->remove(privctx->dbenv, config.db_dir, 0); - privctx->dbenv = NULL; + if (ret == 0) { + privctx->dbenv->set_errcall(privctx->dbenv, &db4_errfunc); + 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); - ret = curdb->upgrade(curdb, buf, 0); + curdb->upgrade(curdb, buf, 0); curdb->close(curdb, 0); } else { logthing(LOGTHING_ERROR, "Error upgrading DB %s : %s", @@ -196,9 +227,21 @@ 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); + } else { + logthing(LOGTHING_ERROR, "Error upgrading DB %s : %s", + buf, + db_strerror(ret)); + } + + ret = db_create(&curdb, NULL, 0); + if (ret == 0) { + snprintf(buf, sizeof(buf) - 1, "%s/id32db", dbctx->config->location); logthing(LOGTHING_DEBUG, "Upgrading %s", buf); - ret = curdb->upgrade(curdb, buf, 0); + curdb->upgrade(curdb, buf, 0); curdb->close(curdb, 0); } else { logthing(LOGTHING_ERROR, "Error upgrading DB %s : %s", @@ -208,9 +251,9 @@ 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/id64db", dbctx->config->location); logthing(LOGTHING_DEBUG, "Upgrading %s", buf); - ret = curdb->upgrade(curdb, buf, 0); + curdb->upgrade(curdb, buf, 0); curdb->close(curdb, 0); } else { logthing(LOGTHING_ERROR, "Error upgrading DB %s : %s", @@ -220,9 +263,9 @@ 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/skshashdb", dbctx->config->location); logthing(LOGTHING_DEBUG, "Upgrading %s", buf); - ret = curdb->upgrade(curdb, buf, 0); + curdb->upgrade(curdb, buf, 0); curdb->close(curdb, 0); } else { logthing(LOGTHING_ERROR, "Error upgrading DB %s : %s", @@ -232,9 +275,9 @@ 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/subkeydb", dbctx->config->location); logthing(LOGTHING_DEBUG, "Upgrading %s", buf); - ret = curdb->upgrade(curdb, buf, 0); + curdb->upgrade(curdb, buf, 0); curdb->close(curdb, 0); } else { logthing(LOGTHING_ERROR, "Error upgrading DB %s : %s", @@ -242,7 +285,7 @@ static int db4_upgradedb(struct onak_db4_dbctx *privctx) db_strerror(ret)); } - snprintf(buf, sizeof(buf) - 1, "%s/%s", config.db_dir, + snprintf(buf, sizeof(buf) - 1, "%s/%s", dbctx->config->location, DB4_UPGRADE_FILE); unlink(buf); @@ -250,68 +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 */ - - 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; - } - } - - ret = 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) { @@ -321,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)); @@ -332,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, @@ -349,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, @@ -362,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, @@ -402,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); } /** @@ -422,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; @@ -431,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); @@ -444,6 +511,11 @@ static int db4_fetch_key_text(struct onak_dbctx *dbctx, const char *search, &cursor, 0); /* flags */ + if (ret != 0) { + db4_endtrans(dbctx); + break; + } + memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); key.data = curword->object; @@ -456,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); @@ -481,14 +550,16 @@ 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) { free(data.data); data.data = NULL; } - ret = cursor->c_close(cursor); + cursor->c_close(cursor); cursor = NULL; firstpass = 0; db4_endtrans(dbctx); @@ -502,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); } @@ -522,19 +593,26 @@ 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, &cursor, 0); /* flags */ + if (ret != 0) { + return 0; + } + memset(&key, 0, sizeof(key)); 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, @@ -542,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); } - ret = cursor->c_close(cursor); + 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. @@ -600,36 +687,23 @@ static int db4_delete_key(struct onak_dbctx *dbctx, wordlist = makewordlist(wordlist, uids[i]); } - ret = privctx->worddb->cursor(privctx->worddb, + privctx->worddb->cursor(privctx->worddb, privctx->txn, &cursor, 0); /* flags */ 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, @@ -640,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 ")", @@ -651,21 +725,40 @@ static int db4_delete_key(struct onak_dbctx *dbctx, } } } - ret = cursor->c_close(cursor); + cursor->c_close(cursor); cursor = NULL; - ret = privctx->skshashdb->cursor(privctx->skshashdb, + /* + * Free our UID and word lists. + */ + llfree(wordlist, NULL); + for (i = 0; uids[i] != NULL; i++) { + free(uids[i]); + uids[i] = NULL; + } + free(uids); + uids = NULL; + } + + if (!deadlock) { + privctx->id32db->cursor(privctx->id32db, privctx->txn, &cursor, 0); /* flags */ - get_skshash(publickey, &hash); + 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 = hash.hash; - key.size = sizeof(hash.hash); - data.data = &keyid; - data.size = sizeof(keyid); + key.data = &shortkeyid; + key.size = sizeof(shortkeyid); + data.data = fp->fp; + data.size = fp->length; ret = cursor->c_get(cursor, &key, @@ -676,9 +769,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 short keyid: %s " "(0x%016" PRIX64 ")", db_strerror(ret), keyid); @@ -687,50 +780,26 @@ static int db4_delete_key(struct onak_dbctx *dbctx, } } - ret = cursor->c_close(cursor); - cursor = NULL; - - /* - * Free our UID and word lists. - */ - llfree(wordlist, NULL); - for (i = 0; uids[i] != NULL; i++) { - free(uids[i]); - uids[i] = NULL; - } - free(uids); - uids = NULL; - free_publickey(publickey); - publickey = NULL; - } - - if (!deadlock) { - ret = privctx->id32db->cursor(privctx->id32db, - privctx->txn, - &cursor, - 0); /* flags */ - - shortkeyid = keyid & 0xFFFFFFFF; - + /* 64 bit key mapping to fingerprint */ memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); - key.data = &shortkeyid; - key.size = sizeof(shortkeyid); - data.data = &keyid; - data.size = sizeof(keyid); + key.data = &keyid; + key.size = sizeof(keyid); + data.data = fp->fp; + data.size = fp->length; - ret = cursor->c_get(cursor, + ret = cursor64->c_get(cursor64, &key, &data, DB_GET_BOTH); if (ret == 0) { - ret = cursor->c_del(cursor, 0); + ret = cursor64->c_del(cursor64, 0); } - if (ret != 0) { + if (ret != 0 && ret != DB_NOTFOUND) { logthing(LOGTHING_ERROR, - "Problem deleting short keyid: %s " + "Problem deleting keyid: %s " "(0x%016" PRIX64 ")", db_strerror(ret), keyid); @@ -741,13 +810,14 @@ static int db4_delete_key(struct onak_dbctx *dbctx, 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 ")", @@ -758,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, @@ -776,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 ")", @@ -786,21 +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; } - ret = cursor->c_close(cursor); + 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); + /* 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); + } + + 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 = &keyid; - key.size = sizeof(keyid); + key.data = fp->fp; + key.size = fp->length; - keydb(privctx, keyid)->del(keydb(privctx, keyid), + keydb_fp(privctx, fp)->del(keydb_fp(privctx, fp), privctx->txn, &key, 0); /* flags */ @@ -840,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); } @@ -867,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); } /* @@ -886,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, @@ -920,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); @@ -936,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, @@ -983,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; @@ -993,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, @@ -1011,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, @@ -1037,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, @@ -1060,6 +1246,7 @@ static int db4_store_key(struct onak_dbctx *dbctx, deadlock = true; } } + i++; } if (subkeyids != NULL) { free(subkeyids); @@ -1073,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, @@ -1129,6 +1316,10 @@ static int db4_iterate_keys(struct onak_dbctx *dbctx, &cursor, 0); /* flags */ + if (ret != 0) { + continue; + } + memset(&dbkey, 0, sizeof(dbkey)); memset(&data, 0, sizeof(data)); ret = cursor->c_get(cursor, &dbkey, &data, DB_NEXT); @@ -1159,7 +1350,7 @@ static int db4_iterate_keys(struct onak_dbctx *dbctx, db_strerror(ret)); } - ret = cursor->c_close(cursor); + cursor->c_close(cursor); cursor = NULL; } @@ -1172,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" /** @@ -1196,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; @@ -1229,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; @@ -1245,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); @@ -1254,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)) { @@ -1269,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) { @@ -1309,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 @@ -1331,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, @@ -1340,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); } @@ -1350,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, @@ -1369,10 +1566,12 @@ 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)); - privctx->dbenv->close(privctx->dbenv, 0); - privctx->dbenv = NULL; + if (privctx->dbenv != NULL) { + privctx->dbenv->close(privctx->dbenv, 0); + privctx->dbenv = NULL; + } } } @@ -1462,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) { @@ -1521,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; @@ -1530,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;