From 8e0907be1d73011075a99a0c029c56664e12843e Mon Sep 17 00:00:00 2001 From: Jonathan McDowell Date: Fri, 8 Nov 2013 23:02:45 -0800 Subject: [PATCH] Use dynamic context for all backend databases Rather than defining a static set of database functions use a well known initialisation function for each database backend that then returns a database context structure. This structure contains function pointers for all of the functions previously held in dbstructs as well as a private instance context pointer. For the moment this doesn't provide any change to behaviour, but it provides the initial preparation for allowing multiple database instance (whether of the same or differing types) to be used at the same time. --- Makefile.in | 4 +- add.c | 7 +- gpgwww.c | 26 +- hashquery.c | 14 +- keyd.c | 34 +- keydb.c | 37 +- keydb.h | 57 +-- keydb_db4.c | 1054 ++++++++++++++++++++++++----------------------- keydb_dynamic.c | 622 +++++++++------------------- keydb_file.c | 120 +++--- keydb_fs.c | 197 +++++---- keydb_hkp.c | 224 +++++----- keydb_keyd.c | 319 +++++++------- keydb_pg.c | 217 ++++++---- keydctl.c | 2 +- keyindex.c | 24 +- keyindex.h | 4 +- lookup.c | 34 +- maxpath.c | 29 +- onak-conf.c | 4 +- onak-conf.h | 4 +- onak.c | 45 +- sixdegrees.c | 32 +- stats.c | 24 +- stats.h | 9 +- wotsap.c | 37 +- 26 files changed, 1562 insertions(+), 1618 deletions(-) diff --git a/Makefile.in b/Makefile.in index da116ac..76d7fc4 100644 --- a/Makefile.in +++ b/Makefile.in @@ -142,12 +142,12 @@ onak: onak.o cleankey.o $(CORE_OBJS) $(KEYDB_OBJ) onak-conf.o: onak-conf.c onak-conf.h $(CC) $(CFLAGS) -DCONFIGFILE=\"@sysconfdir@/onak.conf\" \ - -DDBFUNCS=keydb_@DBTYPE@_funcs -c onak-conf.c + -DDBINIT=keydb_@DBTYPE@_init -c onak-conf.c # HACK: onak-conf.o needs to be able to see keydb_@DBTYPE@_funcs, but # keydctl doesn't want to link against the DB stuff. To be fixed more cleanly. keydctl.o: keydctl.c keyd.h - $(CC) $(CFLAGS) -DDBFUNCS=keydb_@DBTYPE@_funcs -c keydctl.c + $(CC) $(CFLAGS) -DDBINIT=keydb_@DBTYPE@_init -c keydctl.c onak-mail.pl: onak-mail.pl.in sed 's:@CONFIG@:@sysconfdir@/onak.conf:g' < onak-mail.pl.in > onak-mail.pl diff --git a/add.c b/add.c index 6f919be..4e03719 100644 --- a/add.c +++ b/add.c @@ -43,6 +43,7 @@ int main(int argc, char *argv[]) struct buffer_ctx ctx; int count = 0; int i; + struct onak_dbctx *dbctx; memset(&ctx, 0, sizeof(ctx)); @@ -88,13 +89,13 @@ int main(int argc, char *argv[]) fclose(stderr); } catchsignals(); - config.dbbackend->initdb(false); + dbctx = config.dbinit(false); count = cleankeys(keys); logthing(LOGTHING_INFO, "%d keys cleaned.", count); - count = config.dbbackend->update_keys(&keys, true); + count = dbctx->update_keys(dbctx, &keys, true); logthing(LOGTHING_NOTICE, "Got %d new keys.", count); @@ -103,7 +104,7 @@ int main(int argc, char *argv[]) keys = NULL; } - config.dbbackend->cleanupdb(); + dbctx->cleanupdb(dbctx); } else { puts("No OpenPGP packets found in input."); end_html(); diff --git a/gpgwww.c b/gpgwww.c index 07b448e..6615887 100644 --- a/gpgwww.c +++ b/gpgwww.c @@ -62,7 +62,8 @@ int parsecgistuff(char **cgiparams, uint64_t *from, uint64_t *to) return op; } -int getkeyspath(uint64_t have, uint64_t want, int count) +int getkeyspath(struct onak_dbctx *dbctx, + uint64_t have, uint64_t want, int count) { struct openpgp_publickey *publickey = NULL; struct openpgp_packet_list *packets = NULL; @@ -71,14 +72,14 @@ int getkeyspath(uint64_t have, uint64_t want, int count) uint64_t fullhave, fullwant; int pathlen = 0; - fullhave = config.dbbackend->getfullkeyid(have); - fullwant = config.dbbackend->getfullkeyid(want); + fullhave = dbctx->getfullkeyid(dbctx, have); + fullwant = dbctx->getfullkeyid(dbctx, want); /* * Make sure the keys we have and want are in the cache. */ - config.dbbackend->cached_getkeysigs(fullhave); - config.dbbackend->cached_getkeysigs(fullwant); + dbctx->cached_getkeysigs(dbctx, fullhave); + dbctx->cached_getkeysigs(dbctx, fullwant); if ((keyinfoa = findinhash(fullhave)) == NULL) { return 1; @@ -92,7 +93,7 @@ int getkeyspath(uint64_t have, uint64_t want, int count) * Fill the tree info up. */ initcolour(true); - findpath(keyinfoa, keyinfob); + findpath(dbctx, keyinfoa, keyinfob); keyinfob->parent = 0; if (keyinfoa->colour == 0) { pathlen = count; @@ -104,7 +105,7 @@ int getkeyspath(uint64_t have, uint64_t want, int count) curkey = findinhash(keyinfoa->parent); while (curkey != NULL && curkey->keyid != 0) { if (curkey->keyid != fullwant && - config.dbbackend->fetch_key_id( + dbctx->fetch_key_id(dbctx, curkey->keyid, &publickey, false)) { flatten_publickey(publickey, @@ -125,7 +126,7 @@ int getkeyspath(uint64_t have, uint64_t want, int count) /* * Add the destination key to the list of returned keys. */ - if (config.dbbackend->fetch_key_id(fullwant, &publickey, false)) { + if (dbctx->fetch_key_id(dbctx, fullwant, &publickey, false)) { flatten_publickey(publickey, &packets, &list_end); @@ -145,6 +146,7 @@ int main(int argc, char *argv[]) char **cgiparams = NULL; /* Our CGI parameter block */ uint64_t from = 0, to = 0; int op = OP_UNKNOWN; + struct onak_dbctx *dbctx; cgiparams = getcgivars(argc, argv); @@ -181,7 +183,7 @@ int main(int argc, char *argv[]) readconfig(NULL); initlogthing("gpgwww", config.logfile); catchsignals(); - config.dbbackend->initdb(true); + dbctx = config.dbinit(true); inithash(); logthing(LOGTHING_NOTICE, "Looking for path from 0x%016" PRIX64 " to 0x%016" @@ -189,12 +191,12 @@ int main(int argc, char *argv[]) from, to); if (op == OP_GET) { - getkeyspath(from, to, 3); + getkeyspath(dbctx, from, to, 3); } else { - dofindpath(from, to, true, 3); + dofindpath(dbctx, from, to, true, 3); } destroyhash(); - config.dbbackend->cleanupdb(); + dbctx->cleanupdb(dbctx); cleanuplogthing(); cleanupconfig(); diff --git a/hashquery.c b/hashquery.c index 478c20f..965eaf9 100644 --- a/hashquery.c +++ b/hashquery.c @@ -47,6 +47,7 @@ int main(int argc, char *argv[]) uint8_t **hashes; struct buffer_ctx cgipostbuf; struct openpgp_publickey **keys; + struct onak_dbctx *dbctx; readconfig(NULL); initlogthing("hashquery", config.logfile); @@ -88,15 +89,16 @@ int main(int argc, char *argv[]) doerror("Couldn't allocate memory for reply.\n"); } - if (config.dbbackend->fetch_key_skshash == NULL) { + catchsignals(); + dbctx = config.dbinit(false); + + if (dbctx->fetch_key_skshash == NULL) { + dbctx->cleanupdb(dbctx); doerror("Can't fetch by skshash with this backend."); } - catchsignals(); - config.dbbackend->initdb(false); - for (i = 0; i < count; i++) { - config.dbbackend->fetch_key_skshash( + dbctx->fetch_key_skshash(dbctx, (struct skshash *) hashes[i], &keys[found]); if (keys[found] != NULL) { found++; @@ -107,7 +109,7 @@ int main(int argc, char *argv[]) free(hashes); hashes = NULL; - config.dbbackend->cleanupdb(); + dbctx->cleanupdb(dbctx); puts("Content-Type: pgp/keys\n"); marshal_array(stdout_putchar, NULL, diff --git a/keyd.c b/keyd.c index a89f0e1..f3966db 100644 --- a/keyd.c +++ b/keyd.c @@ -144,7 +144,7 @@ int sock_init(const char *sockname) return fd; } -int sock_do(int fd) +int sock_do(struct onak_dbctx *dbctx, int fd) { uint32_t cmd = KEYD_CMD_UNKNOWN; ssize_t bytes = 0; @@ -197,8 +197,8 @@ int sock_do(int fd) "Fetching 0x%" PRIX64 ", result: %d", keyid, - config.dbbackend-> - fetch_key_id(keyid, + dbctx->fetch_key_id(dbctx, + keyid, &key, false)); if (key != NULL) { storebuf.size = 8192; @@ -245,8 +245,8 @@ int sock_do(int fd) logthing(LOGTHING_INFO, "Fetching by fingerprint" ", result: %d", - config.dbbackend-> - fetch_key_fp(fp, bytes, + dbctx->fetch_key_fp(dbctx, + fp, bytes, &key, false)); if (key != NULL) { storebuf.size = 8192; @@ -295,8 +295,8 @@ int sock_do(int fd) logthing(LOGTHING_INFO, "Fetching %s, result: %d", search, - config.dbbackend-> - fetch_key_text(search, &key)); + dbctx->fetch_key_text(dbctx, + search, &key)); if (key != NULL) { storebuf.size = 8192; storebuf.buffer = malloc(8192); @@ -357,7 +357,7 @@ int sock_do(int fd) &packets, 0); parse_keys(packets, &key); - config.dbbackend->store_key(key, false, false); + dbctx->store_key(dbctx, key, false, false); free_packet_list(packets); packets = NULL; free_publickey(key); @@ -379,7 +379,7 @@ int sock_do(int fd) "Deleting 0x%" PRIX64 ", result: %d", keyid, - config.dbbackend->delete_key( + dbctx->delete_key(dbctx, keyid, false)); } break; @@ -391,7 +391,7 @@ int sock_do(int fd) ret = 1; } if (ret == 0) { - keyid = config.dbbackend->getfullkeyid(keyid); + keyid = dbctx->getfullkeyid(dbctx, keyid); cmd = sizeof(keyid); write(fd, &cmd, sizeof(cmd)); write(fd, &keyid, sizeof(keyid)); @@ -400,7 +400,7 @@ int sock_do(int fd) case KEYD_CMD_KEYITER: cmd = KEYD_REPLY_OK; write(fd, &cmd, sizeof(cmd)); - config.dbbackend->iterate_keys(iteratefunc, + dbctx->iterate_keys(dbctx, iteratefunc, &fd); bytes = 0; write(fd, &bytes, sizeof(bytes)); @@ -438,9 +438,8 @@ int sock_do(int fd) logthing(LOGTHING_INFO, "Fetching by hash" ", result: %d", - config.dbbackend-> - fetch_key_skshash(&hash, - &key)); + dbctx->fetch_key_skshash(dbctx, + &hash, &key)); if (key != NULL) { storebuf.size = 8192; storebuf.buffer = malloc(8192); @@ -531,6 +530,7 @@ int main(int argc, char *argv[]) char *configfile = NULL; bool foreground = false; int optchar; + struct onak_dbctx *dbctx; while ((optchar = getopt(argc, argv, "c:fh")) != -1 ) { switch (optchar) { @@ -578,7 +578,7 @@ int main(int argc, char *argv[]) maxfd = fd; memset(clients, -1, sizeof (clients)); - config.dbbackend->initdb(false); + dbctx = config.dbinit(false); logthing(LOGTHING_NOTICE, "Accepting connections."); while (!cleanup() && select(maxfd + 1, &rfds, NULL, NULL, NULL) != -1) { @@ -592,7 +592,7 @@ int main(int argc, char *argv[]) FD_ISSET(clients[i], &rfds)) { logthing(LOGTHING_DEBUG, "Handling connection for client %d.", i); - if (sock_do(clients[i])) { + if (sock_do(dbctx, clients[i])) { sock_close(clients[i]); clients[i] = -1; logthing(LOGTHING_DEBUG, @@ -626,7 +626,7 @@ int main(int argc, char *argv[]) } } } - config.dbbackend->cleanupdb(); + dbctx->cleanupdb(dbctx); sock_close(fd); unlink(sockname); } diff --git a/keydb.c b/keydb.c index ac70640..14418fb 100644 --- a/keydb.c +++ b/keydb.c @@ -43,14 +43,14 @@ * keyid2uid - Takes a keyid and returns the primary UID for it. * @keyid: The keyid to lookup. */ -char *generic_keyid2uid(uint64_t keyid) +char *generic_keyid2uid(struct onak_dbctx *dbctx, uint64_t keyid) { struct openpgp_publickey *publickey = NULL; struct openpgp_signedpacket_list *curuid = NULL; char buf[1024]; buf[0]=0; - if (config.dbbackend->fetch_key_id(keyid, &publickey, false) && + if (dbctx->fetch_key_id(dbctx, keyid, &publickey, false) && publickey != NULL) { curuid = publickey->uids; while (curuid != NULL && buf[0] == 0) { @@ -82,13 +82,14 @@ char *generic_keyid2uid(uint64_t keyid) * indexing and doing stats bits. If revoked is non-NULL then if the key * is revoked it's set to true. */ -struct ll *generic_getkeysigs(uint64_t keyid, bool *revoked) +struct ll *generic_getkeysigs(struct onak_dbctx *dbctx, + uint64_t keyid, bool *revoked) { struct ll *sigs = NULL; struct openpgp_signedpacket_list *uids = NULL; struct openpgp_publickey *publickey = NULL; - config.dbbackend->fetch_key_id(keyid, &publickey, false); + dbctx->fetch_key_id(dbctx, keyid, &publickey, false); if (publickey != NULL) { for (uids = publickey->uids; uids != NULL; uids = uids->next) { @@ -112,7 +113,7 @@ struct ll *generic_getkeysigs(uint64_t keyid, bool *revoked) * getkeysigs function above except we use the hash module to cache the * data so if we need it again it's already loaded. */ -struct ll *generic_cached_getkeysigs(uint64_t keyid) +struct ll *generic_cached_getkeysigs(struct onak_dbctx *dbctx, uint64_t keyid) { struct stats_key *key = NULL; struct stats_key *signedkey = NULL; @@ -127,7 +128,7 @@ struct ll *generic_cached_getkeysigs(uint64_t keyid) key = findinhash(keyid); if (key == NULL || key->gotsigs == false) { - sigs = config.dbbackend->getkeysigs(keyid, &revoked); + sigs = dbctx->getkeysigs(dbctx, keyid, &revoked); if (sigs == NULL) { return NULL; } @@ -155,12 +156,12 @@ struct ll *generic_cached_getkeysigs(uint64_t 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. */ -uint64_t generic_getfullkeyid(uint64_t keyid) +uint64_t generic_getfullkeyid(struct onak_dbctx *dbctx, uint64_t keyid) { struct openpgp_publickey *publickey = NULL; if (keyid < 0x100000000LL) { - config.dbbackend->fetch_key_id(keyid, &publickey, false); + dbctx->fetch_key_id(dbctx, keyid, &publickey, false); if (publickey != NULL) { get_keyid(publickey, &keyid); free_publickey(publickey); @@ -186,7 +187,8 @@ uint64_t generic_getfullkeyid(uint64_t keyid) * we had before to what we have now (ie the set of data that was added to * the DB). Returns the number of entirely new keys added. */ -int generic_update_keys(struct openpgp_publickey **keys, bool sendsync) +int generic_update_keys(struct onak_dbctx *dbctx, + struct openpgp_publickey **keys, bool sendsync) { struct openpgp_publickey *curkey = NULL; struct openpgp_publickey *oldkey = NULL; @@ -196,12 +198,12 @@ int generic_update_keys(struct openpgp_publickey **keys, bool sendsync) uint64_t keyid; for (curkey = *keys; curkey != NULL; curkey = curkey->next) { - intrans = config.dbbackend->starttrans(); + intrans = dbctx->starttrans(dbctx); get_keyid(curkey, &keyid); logthing(LOGTHING_INFO, "Fetching key 0x%" PRIX64 ", result: %d", keyid, - config.dbbackend->fetch_key_id(keyid, &oldkey, + dbctx->fetch_key_id(dbctx, keyid, &oldkey, intrans)); /* @@ -227,7 +229,7 @@ int generic_update_keys(struct openpgp_publickey **keys, bool sendsync) prev = curkey; logthing(LOGTHING_INFO, "Merged key; storing updated key."); - config.dbbackend->store_key(oldkey, intrans, + dbctx->store_key(dbctx, oldkey, intrans, true); } free_publickey(oldkey); @@ -235,10 +237,10 @@ int generic_update_keys(struct openpgp_publickey **keys, bool sendsync) } else { logthing(LOGTHING_INFO, "Storing completely new key."); - config.dbbackend->store_key(curkey, intrans, false); + dbctx->store_key(dbctx, curkey, intrans, false); newkeys++; } - config.dbbackend->endtrans(); + dbctx->endtrans(dbctx); intrans = false; } @@ -251,8 +253,9 @@ int generic_update_keys(struct openpgp_publickey **keys, bool sendsync) #endif /* NEED_UPDATEKEYS */ #ifdef NEED_GET_FP -static int generic_fetch_key_fp(uint8_t *fp, size_t fpsize, - struct openpgp_publickey **publickey, bool intrans) +static int generic_fetch_key_fp(struct onak_dbctx *dbctx, + uint8_t *fp, size_t fpsize, + struct openpgp_publickey **publickey, bool intrans) { uint64_t keyid; int i; @@ -273,6 +276,6 @@ static int generic_fetch_key_fp(uint8_t *fp, size_t fpsize, keyid = (keyid << 8) + fp[i]; } - return config.dbbackend->fetch_key_id(keyid, publickey, intrans); + return dbctx->fetch_key_id(dbctx, keyid, publickey, intrans); } #endif diff --git a/keydb.h b/keydb.h index 6ad9a59..50f969a 100644 --- a/keydb.h +++ b/keydb.h @@ -27,26 +27,16 @@ #include "ll.h" /** - * @brief All of the functions a DB backend exports. + * @brief Context for a database backend */ -struct dbfuncs { -/** - * @brief Initialize the key database. - * @param readonly If we'll only be reading the DB, not writing to it. - * - * This function should be called before any of the other functions in - * this file are called in order to allow the DB to be initialized ready - * for access. - */ - void (*initdb)(bool readonly); - +struct onak_dbctx { /** * @brief De-initialize the key database. * * This function should be called upon program exit to allow the DB to * cleanup after itself. */ - void (*cleanupdb)(void); + void (*cleanupdb)(struct onak_dbctx *); /** * @brief Start a transaction. @@ -55,14 +45,14 @@ struct dbfuncs { * operations on the database to help speed it all up, or if we want * something to only succeed if all relevant operations are successful. */ - bool (*starttrans)(void); + bool (*starttrans)(struct onak_dbctx *); /** * @brief End a transaction. * * Ends a transaction. */ - void (*endtrans)(void); + void (*endtrans)(struct onak_dbctx *); /** * @brief Given a keyid fetch the key from storage. @@ -75,7 +65,8 @@ struct dbfuncs { * * TODO: What about keyid collisions? Should we use fingerprint instead? */ - int (*fetch_key_id)(uint64_t keyid, + int (*fetch_key_id)(struct onak_dbctx *, + uint64_t keyid, struct openpgp_publickey **publickey, bool intrans); @@ -89,7 +80,8 @@ struct dbfuncs { * This function returns a public key from whatever storage mechanism we * are using. */ - int (*fetch_key_fp)(uint8_t *fp, + int (*fetch_key_fp)(struct onak_dbctx *, + uint8_t *fp, size_t fpsize, struct openpgp_publickey **publickey, bool intrans); @@ -107,7 +99,8 @@ struct dbfuncs { * * TODO: Do we store multiple keys of the same id? Or only one and replace it? */ - int (*store_key)(struct openpgp_publickey *publickey, bool intrans, + int (*store_key)(struct onak_dbctx *, + struct openpgp_publickey *publickey, bool intrans, bool update); /** @@ -118,7 +111,7 @@ struct dbfuncs { * This function deletes a public key from whatever storage mechanism we * are using. Returns 0 if the key existed. */ - int (*delete_key)(uint64_t keyid, bool intrans); + int (*delete_key)(struct onak_dbctx *, uint64_t keyid, bool intrans); /** * @brief Trys to find the keys that contain the supplied text. @@ -128,7 +121,7 @@ struct dbfuncs { * This function searches for the supplied text and returns the keys that * contain it. */ - int (*fetch_key_text)(const char *search, + int (*fetch_key_text)(struct onak_dbctx *, const char *search, struct openpgp_publickey **publickey); /** @@ -139,7 +132,8 @@ struct dbfuncs { * This function looks for the key that is referenced by the supplied * SKS hash and returns it. */ - int (*fetch_key_skshash)(const struct skshash *hash, + int (*fetch_key_skshash)(struct onak_dbctx *, + const struct skshash *hash, struct openpgp_publickey **publickey); /** @@ -156,7 +150,8 @@ struct dbfuncs { * If sendsync is true then we send out a keysync mail to our sync peers * with the update. */ - int (*update_keys)(struct openpgp_publickey **keys, bool sendsync); + int (*update_keys)(struct onak_dbctx *, + struct openpgp_publickey **keys, bool sendsync); /** * @brief Takes a keyid and returns the primary UID for it. @@ -165,7 +160,7 @@ struct dbfuncs { * This function returns a UID for the given key. Returns NULL if the key * isn't found. */ - char * (*keyid2uid)(uint64_t keyid); + char * (*keyid2uid)(struct onak_dbctx *, uint64_t keyid); /** * @brief Gets a linked list of the signatures on a key. @@ -176,7 +171,8 @@ struct dbfuncs { * indexing and doing stats bits. If revoked is non-NULL then if the key * is revoked it's set to true. */ - struct ll * (*getkeysigs)(uint64_t keyid, bool *revoked); + struct ll * (*getkeysigs)(struct onak_dbctx *, + uint64_t keyid, bool *revoked); /** * @brief Gets the signatures on a key. @@ -185,7 +181,8 @@ struct dbfuncs { * This function gets the signatures on a key. It's the same as the * getkeysigs function above except we use the hash module to cache the */ - struct ll * (*cached_getkeysigs)(uint64_t keyid); + struct ll * (*cached_getkeysigs)(struct onak_dbctx *, + uint64_t keyid); /** * @brief Maps a 32 bit key id to a 64 bit one. @@ -194,7 +191,7 @@ struct dbfuncs { * This function maps a 32 bit key id to the full 64 bit one. It returns the * full keyid. If the key isn't found a keyid of 0 is returned. */ - uint64_t (*getfullkeyid)(uint64_t keyid); + uint64_t (*getfullkeyid)(struct onak_dbctx *, uint64_t keyid); /** * @brief call a function once for each key in the db. @@ -207,8 +204,14 @@ struct dbfuncs { * * Returns the number of keys we iterated over. */ - int (*iterate_keys)(void (*iterfunc)(void *ctx, + int (*iterate_keys)(struct onak_dbctx *, + void (*iterfunc)(void *ctx, struct openpgp_publickey *key), void *ctx); + +/** + * @brief Private backend context information. + */ + void *priv; }; #endif /* __KEYDB_H__ */ diff --git a/keydb_db4.c b/keydb_db4.c index dae8a2a..9d5dd90 100644 --- a/keydb_db4.c +++ b/keydb_db4.c @@ -44,53 +44,24 @@ #define DB4_UPGRADE_FILE "db_upgrade.lck" -/** - * dbenv - our database environment. - */ -static DB_ENV *dbenv = NULL; - -/** - * numdb - The number of database files we have. - */ -static int numdbs = 16; - -/** - * dbconn - our connections to the key database files. - */ -static DB **dbconns = NULL; - -/** - * worddb - our connection to the word database. - */ -static DB *worddb = NULL; - -/** - * id32db - our connection to the 32bit ID database. - */ -static DB *id32db = NULL; - -/** - * skshashdb - our connection to the SKS hash database. - */ -static DB *skshashdb = NULL; - -/** - * subkeydb - our connection to the subkey ID lookup database. - */ -static DB *subkeydb = NULL; - -/** - * txn - our current transaction id. - */ -static DB_TXN *txn = NULL; +struct onak_db4_dbctx { + DB_ENV *dbenv; /* The database environment context */ + int numdbs; /* Number of data databases in use */ + 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 *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(uint64_t keyid) +DB *keydb(struct onak_db4_dbctx *privctx, uint64_t keyid) { uint64_t keytrun; keytrun = keyid >> 8; - return(dbconns[keytrun % numdbs]); + return(privctx->dbconns[keytrun % privctx->numdbs]); } /** @@ -122,16 +93,17 @@ static void db4_errfunc(const DB_ENV *edbenv, const char *errpfx, * operations on the database to help speed it all up, or if we want * something to only succeed if all relevant operations are successful. */ -static bool db4_starttrans(void) +static bool db4_starttrans(struct onak_dbctx *dbctx) { + struct onak_db4_dbctx *privctx = (struct onak_db4_dbctx *) dbctx->priv; int ret; - log_assert(dbenv != NULL); - log_assert(txn == NULL); + log_assert(privctx->dbenv != NULL); + log_assert(privctx->txn == NULL); - ret = dbenv->txn_begin(dbenv, + ret = privctx->dbenv->txn_begin(privctx->dbenv, NULL, /* No parent transaction */ - &txn, + &privctx->txn, 0); if (ret != 0) { logthing(LOGTHING_CRITICAL, @@ -148,14 +120,15 @@ static bool db4_starttrans(void) * * Ends a transaction. */ -static void db4_endtrans(void) +static void db4_endtrans(struct onak_dbctx *dbctx) { + struct onak_db4_dbctx *privctx = (struct onak_db4_dbctx *) dbctx->priv; int ret; - log_assert(dbenv != NULL); - log_assert(txn != NULL); + log_assert(privctx->dbenv != NULL); + log_assert(privctx->txn != NULL); - ret = txn->commit(txn, + ret = privctx->txn->commit(privctx->txn, 0); if (ret != 0) { logthing(LOGTHING_CRITICAL, @@ -163,52 +136,11 @@ static void db4_endtrans(void) db_strerror(ret)); exit(1); } - txn = NULL; + privctx->txn = NULL; return; } -/** - * cleanupdb - De-initialize the key database. - * - * This function should be called upon program exit to allow the DB to - * cleanup after itself. - */ -static void db4_cleanupdb(void) -{ - int i = 0; - - if (dbenv != NULL) { - dbenv->txn_checkpoint(dbenv, 0, 0, 0); - if (subkeydb != NULL) { - subkeydb->close(subkeydb, 0); - subkeydb = NULL; - } - if (skshashdb != NULL) { - skshashdb->close(skshashdb, 0); - skshashdb = NULL; - } - if (id32db != NULL) { - id32db->close(id32db, 0); - id32db = NULL; - } - if (worddb != NULL) { - worddb->close(worddb, 0); - worddb = NULL; - } - for (i = 0; i < numdbs; i++) { - if (dbconns[i] != NULL) { - dbconns[i]->close(dbconns[i], 0); - dbconns[i] = NULL; - } - } - free(dbconns); - dbconns = NULL; - dbenv->close(dbenv, 0); - dbenv = NULL; - } -} - /** * db4_upgradedb - Upgrade a DB4 database * @@ -216,7 +148,7 @@ static void db4_cleanupdb(void) * we're running with a newer version of db4 than the database was * created with. */ -static int db4_upgradedb(int numdb) +static int db4_upgradedb(struct onak_db4_dbctx *privctx) { DB *curdb = NULL; int ret; @@ -243,11 +175,11 @@ static int db4_upgradedb(int numdb) close(lockfile_fd); logthing(LOGTHING_NOTICE, "Upgrading DB4 database"); - ret = db_env_create(&dbenv, 0); - dbenv->set_errcall(dbenv, &db4_errfunc); - dbenv->remove(dbenv, config.db_dir, 0); - dbenv = NULL; - for (i = 0; i < numdb; i++) { + 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; + 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", @@ -318,372 +250,100 @@ static int db4_upgradedb(int numdb) } /** - * initdb - Initialize the key database. + * getfullkeyid - Maps a 32bit key id to a 64bit one. + * @keyid: The 32bit keyid. * - * This function should be called before any of the other functions in - * this file are called in order to allow the DB to be initialized ready - * for access. + * 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 void db4_initdb(bool readonly) +static uint64_t db4_getfullkeyid(struct onak_dbctx *dbctx, uint64_t keyid) { - char buf[1024]; - FILE *numdb = NULL; - int ret = 0; - int i = 0; - uint32_t flags = 0; - struct stat statbuf; - int maxlocks; - - snprintf(buf, sizeof(buf) - 1, "%s/%s", config.db_dir, - DB4_UPGRADE_FILE); - ret = stat(buf, &statbuf); - while ((ret == 0) || (errno != ENOENT)) { - if (ret != 0) { - logthing(LOGTHING_CRITICAL, "Couldn't stat upgrade " - "lock file: %s (%d)", strerror(errno), ret); - exit(1); - } - logthing(LOGTHING_DEBUG, "DB4 upgrade in progress; waiting."); - sleep(5); - ret = stat(buf, &statbuf); - } - ret = 0; - - snprintf(buf, sizeof(buf) - 1, "%s/num_keydb", config.db_dir); - numdb = fopen(buf, "r"); - if (numdb != NULL) { - if (fgets(buf, sizeof(buf), numdb) != NULL) { - numdbs = atoi(buf); - } - fclose(numdb); - } else if (!readonly) { - logthing(LOGTHING_ERROR, "Couldn't open num_keydb: %s", - strerror(errno)); - numdb = fopen(buf, "w"); - if (numdb != NULL) { - fprintf(numdb, "%d", numdbs); - fclose(numdb); - } else { - logthing(LOGTHING_ERROR, - "Couldn't write num_keydb: %s", - strerror(errno)); - } - } + struct onak_db4_dbctx *privctx = (struct onak_db4_dbctx *) dbctx->priv; + DBT key, data; + DBC *cursor = NULL; + uint32_t shortkeyid = 0; + int ret = 0; - dbconns = calloc(numdbs, sizeof (DB *)); - if (dbconns == NULL) { - logthing(LOGTHING_CRITICAL, - "Couldn't allocate memory for dbconns"); - ret = 1; - } + if (keyid < 0x100000000LL) { + ret = privctx->id32db->cursor(privctx->id32db, + privctx->txn, + &cursor, + 0); /* flags */ - if (ret == 0) { - ret = db_env_create(&dbenv, 0); - if (ret != 0) { - logthing(LOGTHING_CRITICAL, - "db_env_create: %s", db_strerror(ret)); - } - } + shortkeyid = keyid & 0xFFFFFFFF; - /* - * 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; - } - dbenv->set_lk_max_locks(dbenv, maxlocks); - dbenv->set_lk_max_objects(dbenv, maxlocks); + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = &shortkeyid; + key.size = sizeof(shortkeyid); + data.flags = DB_DBT_MALLOC; - /* - * Enable deadlock detection so that we don't block indefinitely on - * anything. What we really want is simple 2 state locks, but I'm not - * sure how to make the standard DB functions do that yet. - */ - if (ret == 0) { - dbenv->set_errcall(dbenv, &db4_errfunc); - ret = dbenv->set_lk_detect(dbenv, DB_LOCK_DEFAULT); - if (ret != 0) { - logthing(LOGTHING_CRITICAL, - "db_env_create: %s", db_strerror(ret)); - } - } + ret = cursor->c_get(cursor, + &key, + &data, + DB_SET); - if (ret == 0) { - ret = dbenv->open(dbenv, config.db_dir, - DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_LOCK | - DB_INIT_TXN | - DB_CREATE, - 0); -#ifdef DB_VERSION_MISMATCH - if (ret == DB_VERSION_MISMATCH) { - dbenv->close(dbenv, 0); - dbenv = NULL; - ret = db4_upgradedb(numdbs); - if (ret == 0) { - ret = db_env_create(&dbenv, 0); - } - if (ret == 0) { - dbenv->set_errcall(dbenv, &db4_errfunc); - dbenv->set_lk_detect(dbenv, DB_LOCK_DEFAULT); - ret = dbenv->open(dbenv, config.db_dir, - DB_INIT_LOG | DB_INIT_MPOOL | - DB_INIT_LOCK | DB_INIT_TXN | - DB_CREATE | DB_RECOVER, - 0); + if (ret == 0) { + keyid = *(uint64_t *) data.data; - if (ret == 0) { - dbenv->txn_checkpoint(dbenv, - 0, - 0, - DB_FORCE); - } + if (data.data != NULL) { + free(data.data); + data.data = NULL; } } -#endif - if (ret != 0) { - logthing(LOGTHING_CRITICAL, - "Error opening db environment: %s (%s)", - config.db_dir, - db_strerror(ret)); - dbenv->close(dbenv, 0); - dbenv = NULL; - } - } - if (ret == 0) { - db4_starttrans(); + ret = cursor->c_close(cursor); + cursor = NULL; + } - for (i = 0; !ret && i < numdbs; i++) { - ret = db_create(&dbconns[i], dbenv, 0); - if (ret != 0) { - logthing(LOGTHING_CRITICAL, - "db_create: %s", db_strerror(ret)); - } + return keyid; +} - if (ret == 0) { - snprintf(buf, 1023, "keydb.%d.db", i); - flags = DB_CREATE; - if (readonly) { - flags = DB_RDONLY; - } - ret = dbconns[i]->open(dbconns[i], - txn, - buf, - "keydb", - DB_HASH, - flags, - 0664); - if (ret != 0) { - logthing(LOGTHING_CRITICAL, - "Error opening key database:" - " %s (%s)", - buf, - db_strerror(ret)); - } - } - } +/** + * 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) +{ + 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; + if (keyid < 0x100000000LL) { + keyid = db4_getfullkeyid(dbctx, keyid); } - if (ret == 0) { - ret = db_create(&worddb, dbenv, 0); - if (ret != 0) { - logthing(LOGTHING_CRITICAL, "db_create: %s", - db_strerror(ret)); - } - } + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); - if (ret == 0) { - ret = worddb->set_flags(worddb, DB_DUP); - } + data.size = 0; + data.data = NULL; - if (ret == 0) { - ret = worddb->open(worddb, txn, "worddb", "worddb", DB_BTREE, - flags, - 0664); - if (ret != 0) { - logthing(LOGTHING_CRITICAL, - "Error opening word database: %s (%s)", - "worddb", - db_strerror(ret)); - } - } + key.size = sizeof(keyid); + key.data = &keyid; - if (ret == 0) { - ret = db_create(&id32db, dbenv, 0); - if (ret != 0) { - logthing(LOGTHING_CRITICAL, "db_create: %s", - db_strerror(ret)); - } + if (!intrans) { + db4_starttrans(dbctx); } - if (ret == 0) { - ret = id32db->set_flags(id32db, DB_DUP); - } - - if (ret == 0) { - ret = id32db->open(id32db, txn, "id32db", "id32db", DB_HASH, - flags, - 0664); - if (ret != 0) { - logthing(LOGTHING_CRITICAL, - "Error opening id32 database: %s (%s)", - "id32db", - db_strerror(ret)); - } - } - - if (ret == 0) { - ret = db_create(&skshashdb, dbenv, 0); - if (ret != 0) { - logthing(LOGTHING_CRITICAL, "db_create: %s", - db_strerror(ret)); - } - } - - if (ret == 0) { - ret = skshashdb->open(skshashdb, txn, "skshashdb", - "skshashdb", DB_HASH, - flags, - 0664); - if (ret != 0) { - logthing(LOGTHING_CRITICAL, - "Error opening skshash database: %s (%s)", - "skshashdb", - db_strerror(ret)); - } - } - - if (ret == 0) { - ret = db_create(&subkeydb, dbenv, 0); - if (ret != 0) { - logthing(LOGTHING_CRITICAL, "db_create: %s", - db_strerror(ret)); - } - } - - if (ret == 0) { - ret = subkeydb->open(subkeydb, txn, "subkeydb", "subkeydb", - DB_HASH, - flags, - 0664); - if (ret != 0) { - logthing(LOGTHING_CRITICAL, - "Error opening subkey database: %s (%s)", - "subkeydb", - db_strerror(ret)); - } - } - - if (txn != NULL) { - db4_endtrans(); - } - - if (ret != 0) { - db4_cleanupdb(); - logthing(LOGTHING_CRITICAL, - "Error opening database; exiting"); - exit(EXIT_FAILURE); - } - - return; -} - -/** - * 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(uint64_t keyid) -{ - DBT key, data; - DBC *cursor = NULL; - uint32_t shortkeyid = 0; - int ret = 0; - - if (keyid < 0x100000000LL) { - ret = id32db->cursor(id32db, - 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. - */ -static int db4_fetch_key_id(uint64_t keyid, - struct openpgp_publickey **publickey, - bool intrans) -{ - struct openpgp_packet_list *packets = NULL; - DBT key, data; - int ret = 0; - int numkeys = 0; - struct buffer_ctx fetchbuf; - - if (keyid < 0x100000000LL) { - keyid = db4_getfullkeyid(keyid); - } - - memset(&key, 0, sizeof(key)); - memset(&data, 0, sizeof(data)); - - data.size = 0; - data.data = NULL; - - key.size = sizeof(keyid); - key.data = &keyid; - - if (!intrans) { - db4_starttrans(); - } - - ret = keydb(keyid)->get(keydb(keyid), - txn, - &key, - &data, - 0); /* flags*/ + ret = keydb(privctx, keyid)->get(keydb(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 */ @@ -694,8 +354,8 @@ static int db4_fetch_key_id(uint64_t keyid, key.size = sizeof(keyid); key.data = &keyid; - ret = subkeydb->get(subkeydb, - txn, + ret = privctx->subkeydb->get(privctx->subkeydb, + privctx->txn, &key, &data, 0); /* flags*/ @@ -711,8 +371,8 @@ static int db4_fetch_key_id(uint64_t keyid, key.size = sizeof(keyid); key.data = &keyid; - ret = keydb(keyid)->get(keydb(keyid), - txn, + ret = keydb(privctx, keyid)->get(keydb(privctx, keyid), + privctx->txn, &key, &data, 0); /* flags*/ @@ -736,7 +396,7 @@ static int db4_fetch_key_id(uint64_t keyid, } if (!intrans) { - db4_endtrans(); + db4_endtrans(dbctx); } return (numkeys); @@ -755,9 +415,10 @@ int worddb_cmp(const void *d1, const void *d2) * This function searches for the supplied text and returns the keys that * contain it. */ -static int db4_fetch_key_text(const char *search, +static int db4_fetch_key_text(struct onak_dbctx *dbctx, const char *search, struct openpgp_publickey **publickey) { + struct onak_db4_dbctx *privctx = (struct onak_db4_dbctx *) dbctx->priv; DBC *cursor = NULL; DBT key, data; int ret; @@ -776,10 +437,10 @@ static int db4_fetch_key_text(const char *search, wordlist = makewordlist(wordlist, searchtext); for (curword = wordlist; curword != NULL; curword = curword->next) { - db4_starttrans(); + db4_starttrans(dbctx); - ret = worddb->cursor(worddb, - txn, + ret = privctx->worddb->cursor(privctx->worddb, + privctx->txn, &cursor, 0); /* flags */ @@ -830,7 +491,7 @@ static int db4_fetch_key_text(const char *search, ret = cursor->c_close(cursor); cursor = NULL; firstpass = 0; - db4_endtrans(); + db4_endtrans(dbctx); } llfree(wordlist, NULL); wordlist = NULL; @@ -838,10 +499,10 @@ static int db4_fetch_key_text(const char *search, if (keylist.count > config.maxkeys) { keylist.count = config.maxkeys; } - - db4_starttrans(); + + db4_starttrans(dbctx); for (i = 0; i < keylist.count; i++) { - numkeys += db4_fetch_key_id(keylist.keys[i], + numkeys += db4_fetch_key_id(dbctx, keylist.keys[i], publickey, true); } @@ -849,21 +510,23 @@ static int db4_fetch_key_text(const char *search, free(searchtext); searchtext = NULL; - db4_endtrans(); - + db4_endtrans(dbctx); + return (numkeys); } -static int db4_fetch_key_skshash(const struct skshash *hash, +static int db4_fetch_key_skshash(struct onak_dbctx *dbctx, + const struct skshash *hash, struct openpgp_publickey **publickey) { + struct onak_db4_dbctx *privctx = (struct onak_db4_dbctx *) dbctx->priv; DBT key, data; DBC *cursor = NULL; uint64_t keyid = 0; int ret = 0; - ret = skshashdb->cursor(skshashdb, - txn, + ret = privctx->skshashdb->cursor(privctx->skshashdb, + privctx->txn, &cursor, 0); /* flags */ @@ -890,7 +553,7 @@ static int db4_fetch_key_skshash(const struct skshash *hash, ret = cursor->c_close(cursor); cursor = NULL; - return db4_fetch_key_id(keyid, publickey, false); + return db4_fetch_key_id(dbctx, keyid, publickey, false); } /** @@ -901,8 +564,10 @@ static int db4_fetch_key_skshash(const struct skshash *hash, * This function deletes a public key from whatever storage mechanism we * are using. Returns 0 if the key existed. */ -static int db4_delete_key(uint64_t keyid, bool intrans) +static int db4_delete_key(struct onak_dbctx *dbctx, + uint64_t keyid, bool intrans) { + struct onak_db4_dbctx *privctx = (struct onak_db4_dbctx *) dbctx->priv; struct openpgp_publickey *publickey = NULL; DBT key, data; DBC *cursor = NULL; @@ -919,10 +584,10 @@ static int db4_delete_key(uint64_t keyid, bool intrans) struct skshash hash; if (!intrans) { - db4_starttrans(); + db4_starttrans(dbctx); } - db4_fetch_key_id(keyid, &publickey, true); + db4_fetch_key_id(dbctx, keyid, &publickey, true); /* * Walk through the uids removing the words from the worddb. @@ -934,9 +599,9 @@ static int db4_delete_key(uint64_t keyid, bool intrans) for (i = 0; ret == 0 && uids[i] != NULL; i++) { wordlist = makewordlist(wordlist, uids[i]); } - - ret = worddb->cursor(worddb, - txn, + + ret = privctx->worddb->cursor(privctx->worddb, + privctx->txn, &cursor, 0); /* flags */ @@ -989,8 +654,8 @@ static int db4_delete_key(uint64_t keyid, bool intrans) ret = cursor->c_close(cursor); cursor = NULL; - ret = skshashdb->cursor(skshashdb, - txn, + ret = privctx->skshashdb->cursor(privctx->skshashdb, + privctx->txn, &cursor, 0); /* flags */ get_skshash(publickey, &hash); @@ -1040,8 +705,8 @@ static int db4_delete_key(uint64_t keyid, bool intrans) } if (!deadlock) { - ret = id32db->cursor(id32db, - txn, + ret = privctx->id32db->cursor(privctx->id32db, + privctx->txn, &cursor, 0); /* flags */ @@ -1080,7 +745,8 @@ static int db4_delete_key(uint64_t keyid, bool intrans) memset(&key, 0, sizeof(key)); key.data = &subkeyids[i]; key.size = sizeof(subkeyids[i]); - subkeydb->del(subkeydb, txn, &key, 0); + privctx->subkeydb->del(privctx->subkeydb, + privctx->txn, &key, 0); if (ret != 0) { logthing(LOGTHING_ERROR, "Problem deleting subkey id: %s " @@ -1134,14 +800,14 @@ static int db4_delete_key(uint64_t keyid, bool intrans) key.data = &keyid; key.size = sizeof(keyid); - keydb(keyid)->del(keydb(keyid), - txn, + keydb(privctx, keyid)->del(keydb(privctx, keyid), + privctx->txn, &key, 0); /* flags */ } if (!intrans) { - db4_endtrans(); + db4_endtrans(dbctx); } return deadlock ? (-1) : (ret == DB_NOTFOUND); @@ -1159,9 +825,11 @@ static int db4_delete_key(uint64_t keyid, bool intrans) * the file. If update is true then we delete the old key first, otherwise * we trust that it doesn't exist. */ -static int db4_store_key(struct openpgp_publickey *publickey, bool intrans, +static int db4_store_key(struct onak_dbctx *dbctx, + struct openpgp_publickey *publickey, bool intrans, bool update) { + struct onak_db4_dbctx *privctx = (struct onak_db4_dbctx *) dbctx->priv; struct openpgp_packet_list *packets = NULL; struct openpgp_packet_list *list_end = NULL; struct openpgp_publickey *next = NULL; @@ -1187,7 +855,7 @@ static int db4_store_key(struct openpgp_publickey *publickey, bool intrans, } if (!intrans) { - db4_starttrans(); + db4_starttrans(dbctx); } /* @@ -1199,7 +867,7 @@ static int db4_store_key(struct openpgp_publickey *publickey, bool intrans, * it definitely needs updated. */ if (update) { - deadlock = (db4_delete_key(keyid, true) == -1); + deadlock = (db4_delete_key(dbctx, keyid, true) == -1); } /* @@ -1211,10 +879,10 @@ static int db4_store_key(struct openpgp_publickey *publickey, bool intrans, flatten_publickey(publickey, &packets, &list_end); publickey->next = next; - storebuf.offset = 0; + storebuf.offset = 0; storebuf.size = 8192; storebuf.buffer = malloc(8192); - + write_openpgp_stream(buffer_putchar, &storebuf, packets); /* @@ -1228,8 +896,8 @@ static int db4_store_key(struct openpgp_publickey *publickey, bool intrans, data.size = storebuf.offset; data.data = storebuf.buffer; - ret = keydb(keyid)->put(keydb(keyid), - txn, + ret = keydb(privctx, keyid)->put(keydb(privctx, keyid), + privctx->txn, &key, &data, 0); /* flags*/ @@ -1245,8 +913,8 @@ static int db4_store_key(struct openpgp_publickey *publickey, bool intrans, free(storebuf.buffer); storebuf.buffer = NULL; storebuf.size = 0; - storebuf.offset = 0; - + storebuf.offset = 0; + free_packet_list(packets); packets = NULL; } @@ -1286,9 +954,9 @@ static int db4_store_key(struct openpgp_publickey *publickey, bool intrans, worddb_data[ 8] = (keyid >> 24) & 0xFF; worddb_data[ 9] = (keyid >> 16) & 0xFF; worddb_data[10] = (keyid >> 8) & 0xFF; - worddb_data[11] = keyid & 0xFF; - ret = worddb->put(worddb, - txn, + worddb_data[11] = keyid & 0xFF; + ret = privctx->worddb->put(privctx->worddb, + privctx->txn, &key, &data, 0); @@ -1328,8 +996,8 @@ static int db4_store_key(struct openpgp_publickey *publickey, bool intrans, data.data = &keyid; data.size = sizeof(keyid); - ret = id32db->put(id32db, - txn, + ret = privctx->id32db->put(privctx->id32db, + privctx->txn, &key, &data, 0); @@ -1355,8 +1023,8 @@ static int db4_store_key(struct openpgp_publickey *publickey, bool intrans, data.data = &keyid; data.size = sizeof(keyid); - ret = subkeydb->put(subkeydb, - txn, + ret = privctx->subkeydb->put(privctx->subkeydb, + privctx->txn, &key, &data, 0); @@ -1379,8 +1047,8 @@ static int db4_store_key(struct openpgp_publickey *publickey, bool intrans, data.data = &keyid; data.size = sizeof(keyid); - ret = id32db->put(id32db, - txn, + ret = privctx->id32db->put(privctx->id32db, + privctx->txn, &key, &data, 0); @@ -1408,8 +1076,8 @@ static int db4_store_key(struct openpgp_publickey *publickey, bool intrans, data.data = &keyid; data.size = sizeof(keyid); - ret = skshashdb->put(skshashdb, - txn, + ret = privctx->skshashdb->put(privctx->skshashdb, + privctx->txn, &key, &data, 0); @@ -1424,7 +1092,7 @@ static int db4_store_key(struct openpgp_publickey *publickey, bool intrans, } if (!intrans) { - db4_endtrans(); + db4_endtrans(dbctx); } return deadlock ? -1 : 0 ; @@ -1441,9 +1109,11 @@ static int db4_store_key(struct openpgp_publickey *publickey, bool intrans, * * Returns the number of keys we iterated over. */ -static int db4_iterate_keys(void (*iterfunc)(void *ctx, - struct openpgp_publickey *key), void *ctx) +static int db4_iterate_keys(struct onak_dbctx *dbctx, + void (*iterfunc)(void *ctx, struct openpgp_publickey *key), + void *ctx) { + struct onak_db4_dbctx *privctx = (struct onak_db4_dbctx *) dbctx->priv; DBT dbkey, data; DBC *cursor = NULL; int ret = 0; @@ -1453,8 +1123,8 @@ static int db4_iterate_keys(void (*iterfunc)(void *ctx, struct openpgp_packet_list *packets = NULL; struct openpgp_publickey *key = NULL; - for (i = 0; i < numdbs; i++) { - ret = dbconns[i]->cursor(dbconns[i], + for (i = 0; i < privctx->numdbs; i++) { + ret = privctx->dbconns[i]->cursor(privctx->dbconns[i], NULL, &cursor, 0); /* flags */ @@ -1471,12 +1141,12 @@ static int db4_iterate_keys(void (*iterfunc)(void *ctx, parse_keys(packets, &key); iterfunc(ctx, key); - + free_publickey(key); key = NULL; free_packet_list(packets); packets = NULL; - + memset(&dbkey, 0, sizeof(dbkey)); memset(&data, 0, sizeof(data)); ret = cursor->c_get(cursor, &dbkey, &data, @@ -1492,7 +1162,7 @@ static int db4_iterate_keys(void (*iterfunc)(void *ctx, ret = cursor->c_close(cursor); cursor = NULL; } - + return numkeys; } @@ -1505,21 +1175,363 @@ static int db4_iterate_keys(void (*iterfunc)(void *ctx, #define NEED_GET_FP 1 #include "keydb.c" -struct dbfuncs keydb_db4_funcs = { - .initdb = db4_initdb, - .cleanupdb = db4_cleanupdb, - .starttrans = db4_starttrans, - .endtrans = db4_endtrans, - .fetch_key_id = db4_fetch_key_id, - .fetch_key_fp = generic_fetch_key_fp, - .fetch_key_text = db4_fetch_key_text, - .fetch_key_skshash = db4_fetch_key_skshash, - .store_key = db4_store_key, - .update_keys = generic_update_keys, - .delete_key = db4_delete_key, - .getkeysigs = generic_getkeysigs, - .cached_getkeysigs = generic_cached_getkeysigs, - .keyid2uid = generic_keyid2uid, - .getfullkeyid = db4_getfullkeyid, - .iterate_keys = db4_iterate_keys, -}; +/** + * cleanupdb - De-initialize the key database. + * + * This function should be called upon program exit to allow the DB to + * cleanup after itself. + */ +static void db4_cleanupdb(struct onak_dbctx *dbctx) +{ + struct onak_db4_dbctx *privctx = (struct onak_db4_dbctx *) dbctx->priv; + int i = 0; + + if (privctx->dbenv != NULL) { + privctx->dbenv->txn_checkpoint(privctx->dbenv, 0, 0, 0); + if (privctx->subkeydb != NULL) { + privctx->subkeydb->close(privctx->subkeydb, 0); + privctx->subkeydb = NULL; + } + if (privctx->skshashdb != NULL) { + privctx->skshashdb->close(privctx->skshashdb, 0); + privctx->skshashdb = NULL; + } + if (privctx->id32db != NULL) { + privctx->id32db->close(privctx->id32db, 0); + privctx->id32db = NULL; + } + if (privctx->worddb != NULL) { + privctx->worddb->close(privctx->worddb, 0); + privctx->worddb = NULL; + } + for (i = 0; i < privctx->numdbs; i++) { + if (privctx->dbconns[i] != NULL) { + privctx->dbconns[i]->close(privctx->dbconns[i], + 0); + privctx->dbconns[i] = NULL; + } + } + free(privctx->dbconns); + privctx->dbconns = NULL; + privctx->dbenv->close(privctx->dbenv, 0); + privctx->dbenv = NULL; + } + + free(privctx); + dbctx->priv = NULL; + free(dbctx); +} + +/** + * initdb - Initialize the key database. + * + * This function should be called before any of the other functions in + * this file are called in order to allow the DB to be initialized ready + * for access. + */ +struct onak_dbctx *keydb_db4_init(bool readonly) +{ + char buf[1024]; + FILE *numdb = NULL; + int ret = 0; + int i = 0; + uint32_t flags = 0; + struct stat statbuf; + int maxlocks; + struct onak_dbctx *dbctx; + struct onak_db4_dbctx *privctx; + + dbctx = malloc(sizeof(*dbctx)); + if (dbctx == NULL) { + return NULL; + } + dbctx->priv = privctx = calloc(1, sizeof(*privctx)); + if (privctx == NULL) { + free(dbctx); + return NULL; + } + + /* Default to 16 key data DBs */ + privctx->numdbs = 16; + + snprintf(buf, sizeof(buf) - 1, "%s/%s", config.db_dir, + DB4_UPGRADE_FILE); + ret = stat(buf, &statbuf); + while ((ret == 0) || (errno != ENOENT)) { + if (ret != 0) { + logthing(LOGTHING_CRITICAL, "Couldn't stat upgrade " + "lock file: %s (%d)", strerror(errno), ret); + exit(1); + } + logthing(LOGTHING_DEBUG, "DB4 upgrade in progress; waiting."); + sleep(5); + ret = stat(buf, &statbuf); + } + ret = 0; + + snprintf(buf, sizeof(buf) - 1, "%s/num_keydb", config.db_dir); + numdb = fopen(buf, "r"); + if (numdb != NULL) { + if (fgets(buf, sizeof(buf), numdb) != NULL) { + privctx->numdbs = atoi(buf); + } + fclose(numdb); + } else if (!readonly) { + logthing(LOGTHING_ERROR, "Couldn't open num_keydb: %s", + strerror(errno)); + numdb = fopen(buf, "w"); + if (numdb != NULL) { + fprintf(numdb, "%d", privctx->numdbs); + fclose(numdb); + } else { + logthing(LOGTHING_ERROR, + "Couldn't write num_keydb: %s", + strerror(errno)); + } + } + + privctx->dbconns = calloc(privctx->numdbs, sizeof (DB *)); + if (privctx->dbconns == NULL) { + logthing(LOGTHING_CRITICAL, + "Couldn't allocate memory for dbconns"); + ret = 1; + } + + if (ret == 0) { + ret = db_env_create(&privctx->dbenv, 0); + if (ret != 0) { + logthing(LOGTHING_CRITICAL, + "db_env_create: %s", db_strerror(ret)); + } + } + + /* + * 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; + } + 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 + * anything. What we really want is simple 2 state locks, but I'm not + * sure how to make the standard DB functions do that yet. + */ + if (ret == 0) { + privctx->dbenv->set_errcall(privctx->dbenv, &db4_errfunc); + ret = privctx->dbenv->set_lk_detect(privctx->dbenv, DB_LOCK_DEFAULT); + if (ret != 0) { + logthing(LOGTHING_CRITICAL, + "db_env_create: %s", db_strerror(ret)); + } + } + + if (ret == 0) { + ret = privctx->dbenv->open(privctx->dbenv, config.db_dir, + DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_LOCK | + DB_INIT_TXN | + DB_CREATE, + 0); +#ifdef DB_VERSION_MISMATCH + if (ret == DB_VERSION_MISMATCH) { + privctx->dbenv->close(privctx->dbenv, 0); + privctx->dbenv = NULL; + ret = db4_upgradedb(privctx); + if (ret == 0) { + ret = db_env_create(&privctx->dbenv, 0); + } + if (ret == 0) { + privctx->dbenv->set_errcall(privctx->dbenv, + &db4_errfunc); + privctx->dbenv->set_lk_detect(privctx->dbenv, + DB_LOCK_DEFAULT); + ret = privctx->dbenv->open(privctx->dbenv, + config.db_dir, + DB_INIT_LOG | DB_INIT_MPOOL | + DB_INIT_LOCK | DB_INIT_TXN | + DB_CREATE | DB_RECOVER, + 0); + + if (ret == 0) { + privctx->dbenv->txn_checkpoint( + privctx->dbenv, + 0, + 0, + DB_FORCE); + } + } + } +#endif + if (ret != 0) { + logthing(LOGTHING_CRITICAL, + "Error opening db environment: %s (%s)", + config.db_dir, + db_strerror(ret)); + privctx->dbenv->close(privctx->dbenv, 0); + privctx->dbenv = NULL; + } + } + + if (ret == 0) { + db4_starttrans(dbctx); + + for (i = 0; !ret && i < privctx->numdbs; i++) { + ret = db_create(&privctx->dbconns[i], + privctx->dbenv, 0); + if (ret != 0) { + logthing(LOGTHING_CRITICAL, + "db_create: %s", db_strerror(ret)); + } + + if (ret == 0) { + snprintf(buf, 1023, "keydb.%d.db", i); + flags = DB_CREATE; + if (readonly) { + flags = DB_RDONLY; + } + ret = privctx->dbconns[i]->open( + privctx->dbconns[i], + privctx->txn, + buf, + "keydb", + DB_HASH, + flags, + 0664); + if (ret != 0) { + logthing(LOGTHING_CRITICAL, + "Error opening key database:" + " %s (%s)", + buf, + db_strerror(ret)); + } + } + } + } + + if (ret == 0) { + ret = db_create(&privctx->worddb, privctx->dbenv, 0); + if (ret != 0) { + logthing(LOGTHING_CRITICAL, "db_create: %s", + db_strerror(ret)); + } + } + + if (ret == 0) { + ret = privctx->worddb->set_flags(privctx->worddb, DB_DUP); + } + + if (ret == 0) { + ret = privctx->worddb->open(privctx->worddb, privctx->txn, + "worddb", "worddb", DB_BTREE, + flags, + 0664); + if (ret != 0) { + logthing(LOGTHING_CRITICAL, + "Error opening word database: %s (%s)", + "worddb", + db_strerror(ret)); + } + } + + if (ret == 0) { + ret = db_create(&privctx->id32db, privctx->dbenv, 0); + if (ret != 0) { + logthing(LOGTHING_CRITICAL, "db_create: %s", + db_strerror(ret)); + } + } + + if (ret == 0) { + ret = privctx->id32db->set_flags(privctx->id32db, DB_DUP); + } + + if (ret == 0) { + ret = privctx->id32db->open(privctx->id32db, privctx->txn, + "id32db", "id32db", DB_HASH, + flags, + 0664); + if (ret != 0) { + logthing(LOGTHING_CRITICAL, + "Error opening id32 database: %s (%s)", + "id32db", + db_strerror(ret)); + } + } + + if (ret == 0) { + ret = db_create(&privctx->skshashdb, privctx->dbenv, 0); + if (ret != 0) { + logthing(LOGTHING_CRITICAL, "db_create: %s", + db_strerror(ret)); + } + } + + if (ret == 0) { + ret = privctx->skshashdb->open(privctx->skshashdb, privctx->txn, + "skshashdb", + "skshashdb", DB_HASH, + flags, + 0664); + if (ret != 0) { + logthing(LOGTHING_CRITICAL, + "Error opening skshash database: %s (%s)", + "skshashdb", + db_strerror(ret)); + } + } + + if (ret == 0) { + ret = db_create(&privctx->subkeydb, privctx->dbenv, 0); + if (ret != 0) { + logthing(LOGTHING_CRITICAL, "db_create: %s", + db_strerror(ret)); + } + } + + if (ret == 0) { + ret = privctx->subkeydb->open(privctx->subkeydb, privctx->txn, + "subkeydb", "subkeydb", + DB_HASH, + flags, + 0664); + if (ret != 0) { + logthing(LOGTHING_CRITICAL, + "Error opening subkey database: %s (%s)", + "subkeydb", + db_strerror(ret)); + } + } + + if (privctx->txn != NULL) { + db4_endtrans(dbctx); + } + + if (ret != 0) { + db4_cleanupdb(dbctx); + logthing(LOGTHING_CRITICAL, + "Error opening database; exiting"); + exit(EXIT_FAILURE); + } + + dbctx->cleanupdb = db4_cleanupdb; + 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_text = db4_fetch_key_text; + dbctx->fetch_key_skshash = db4_fetch_key_skshash; + dbctx->store_key = db4_store_key; + dbctx->update_keys = generic_update_keys; + dbctx->delete_key = db4_delete_key; + 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; +} diff --git a/keydb_dynamic.c b/keydb_dynamic.c index 536909a..32695c3 100644 --- a/keydb_dynamic.c +++ b/keydb_dynamic.c @@ -34,519 +34,277 @@ #include "parsekey.h" #include "sendsync.h" -static struct dbfuncs *loaded_backend = NULL; -static void *backend_handle; +struct onak_dynamic_dbctx { + struct onak_dbctx *loadeddbctx; + void *backend_handle; +}; -static bool close_backend(void) +static bool dynamic_starttrans(struct onak_dbctx *dbctx) { - loaded_backend = NULL; - dlclose(backend_handle); - backend_handle = NULL; + struct onak_dynamic_dbctx *privctx = + (struct onak_dynamic_dbctx *) dbctx->priv; - return true; + return privctx->loadeddbctx->starttrans(privctx->loadeddbctx); } -static bool load_backend(void) +static void dynamic_endtrans(struct onak_dbctx *dbctx) { - char *soname = NULL; - char *funcsname = NULL; - - if (loaded_backend != NULL) { - close_backend(); - loaded_backend = NULL; - } - - if (config.use_keyd) { - free(config.db_backend); - config.db_backend = strdup("keyd"); - } - - if (!config.db_backend) { - logthing(LOGTHING_CRITICAL, "No database backend defined."); - exit(EXIT_FAILURE); - } - - if (config.backends_dir == NULL) { - soname = malloc(strlen(config.db_backend) - + strlen("./libkeydb_") - + strlen(".so") - + 1); - - sprintf(soname, "./libkeydb_%s.so", config.db_backend); - } else { - soname = malloc(strlen(config.db_backend) - + strlen("/libkeydb_") - + strlen(".so") - + strlen(config.backends_dir) - + 1); - - sprintf(soname, "%s/libkeydb_%s.so", config.backends_dir, - config.db_backend); - } - - logthing(LOGTHING_INFO, "Loading dynamic backend: %s", soname); + struct onak_dynamic_dbctx *privctx = + (struct onak_dynamic_dbctx *) dbctx->priv; - backend_handle = dlopen(soname, RTLD_LAZY); - if (backend_handle == NULL) { - logthing(LOGTHING_CRITICAL, - "Failed to open handle to library '%s': %s", - soname, dlerror()); - free(soname); - soname = NULL; - exit(EXIT_FAILURE); - } + privctx->loadeddbctx->endtrans(privctx->loadeddbctx); +} - funcsname = malloc(strlen(config.db_backend) - + strlen("keydb_") - + strlen("_funcs") - + 1); - sprintf(funcsname, "keydb_%s_funcs", config.db_backend); +static int dynamic_fetch_key_id(struct onak_dbctx *dbctx, uint64_t keyid, + struct openpgp_publickey **publickey, bool intrans) +{ + struct onak_dynamic_dbctx *privctx = + (struct onak_dynamic_dbctx *) dbctx->priv; - loaded_backend = dlsym(backend_handle, funcsname); - free(funcsname); + return privctx->loadeddbctx->fetch_key_id(privctx->loadeddbctx, keyid, + publickey, intrans); +} - if (loaded_backend == NULL) { - logthing(LOGTHING_CRITICAL, - "Failed to find dbfuncs structure in library " - "'%s' : %s", soname, dlerror()); - free(soname); - soname = NULL; - exit(EXIT_FAILURE); - } - free(soname); - soname = NULL; +static int dynamic_fetch_key_fp(struct onak_dbctx *dbctx, + uint8_t *fp, size_t fpsize, + struct openpgp_publickey **publickey, bool intrans) +{ + struct onak_dynamic_dbctx *privctx = + (struct onak_dynamic_dbctx *) dbctx->priv; - return true; + return privctx->loadeddbctx->fetch_key_fp(privctx->loadeddbctx, + fp, fpsize, publickey, intrans); } -static bool dynamic_starttrans() +static int dynamic_fetch_key_text(struct onak_dbctx *dbctx, + const char *search, + struct openpgp_publickey **publickey) { - if (loaded_backend == NULL) { - load_backend(); - } - - if (loaded_backend != NULL) { - if (loaded_backend->starttrans != NULL) { - return loaded_backend->starttrans(); - } - } + struct onak_dynamic_dbctx *privctx = + (struct onak_dynamic_dbctx *) dbctx->priv; - return false; + return privctx->loadeddbctx->fetch_key_text(privctx->loadeddbctx, + search, publickey); } -static void dynamic_endtrans() +static int dynamic_fetch_key_skshash(struct onak_dbctx *dbctx, + const struct skshash *hash, + struct openpgp_publickey **publickey) { - if (loaded_backend == NULL) { - load_backend(); - } - - if (loaded_backend != NULL) { - if (loaded_backend->endtrans != NULL) { - loaded_backend->endtrans(); - } - } + struct onak_dynamic_dbctx *privctx = + (struct onak_dynamic_dbctx *) dbctx->priv; + + return privctx->loadeddbctx->fetch_key_skshash(privctx->loadeddbctx, + hash, publickey); } -static int dynamic_fetch_key_id(uint64_t keyid, - struct openpgp_publickey **publickey, bool intrans) +static int dynamic_store_key(struct onak_dbctx *dbctx, + struct openpgp_publickey *publickey, bool intrans, + bool update) { - if (loaded_backend == NULL) { - load_backend(); - } - - if (loaded_backend != NULL) { - if (loaded_backend->fetch_key_id != NULL) { - return loaded_backend->fetch_key_id(keyid, - publickey, intrans); - } - } + struct onak_dynamic_dbctx *privctx = + (struct onak_dynamic_dbctx *) dbctx->priv; - return -1; + return privctx->loadeddbctx->store_key(privctx->loadeddbctx, + publickey, intrans, update); } -static int dynamic_fetch_key_fp(uint8_t *fp, size_t fpsize, - struct openpgp_publickey **publickey, bool intrans) +static int dynamic_delete_key(struct onak_dbctx *dbctx, uint64_t keyid, + bool intrans) { - if (loaded_backend == NULL) { - load_backend(); - } - - if (loaded_backend != NULL) { - if (loaded_backend->fetch_key_id != NULL) { - return loaded_backend->fetch_key_fp(fp, fpsize, - publickey, intrans); - } - } + struct onak_dynamic_dbctx *privctx = + (struct onak_dynamic_dbctx *) dbctx->priv; - return -1; + return privctx->loadeddbctx->delete_key(privctx->loadeddbctx, + keyid, intrans); } +static int dynamic_update_keys(struct onak_dbctx *dbctx, + struct openpgp_publickey **keys, bool sendsync) +{ + struct onak_dynamic_dbctx *privctx = + (struct onak_dynamic_dbctx *) dbctx->priv; + return privctx->loadeddbctx->update_keys(privctx->loadeddbctx, + keys, sendsync); +} -static int dynamic_store_key(struct openpgp_publickey *publickey, bool intrans, - bool update) +static struct ll *dynamic_getkeysigs(struct onak_dbctx *dbctx, + uint64_t keyid, bool *revoked) { - if (loaded_backend == NULL) { - load_backend(); - } - - if (loaded_backend != NULL) { - if (loaded_backend->store_key != NULL) { - return loaded_backend->store_key(publickey,intrans,update); - } - } + struct onak_dynamic_dbctx *privctx = + (struct onak_dynamic_dbctx *) dbctx->priv; - return -1; + return privctx->loadeddbctx->getkeysigs(privctx->loadeddbctx, + keyid, revoked); } -static int dynamic_delete_key(uint64_t keyid, bool intrans) +static struct ll *dynamic_cached_getkeysigs(struct onak_dbctx *dbctx, + uint64_t keyid) { - if (loaded_backend == NULL) { - load_backend(); - } - - if (loaded_backend != NULL) { - if (loaded_backend->delete_key != NULL) { - return loaded_backend->delete_key(keyid, intrans); - } - } + struct onak_dynamic_dbctx *privctx = + (struct onak_dynamic_dbctx *) dbctx->priv; - return -1; + return privctx->loadeddbctx->cached_getkeysigs(privctx->loadeddbctx, + keyid); } -static int dynamic_fetch_key_text(const char *search, - struct openpgp_publickey **publickey) +static char *dynamic_keyid2uid(struct onak_dbctx *dbctx, + uint64_t keyid) { - if (loaded_backend == NULL) { - load_backend(); - } - - if (loaded_backend != NULL) { - if (loaded_backend->fetch_key_text != NULL) { - return loaded_backend->fetch_key_text(search, publickey); - } - } + struct onak_dynamic_dbctx *privctx = + (struct onak_dynamic_dbctx *) dbctx->priv; - return -1; + return privctx->loadeddbctx->keyid2uid(privctx->loadeddbctx, + keyid); } -static int dynamic_fetch_key_skshash(const struct skshash *hash, - struct openpgp_publickey **publickey) +static uint64_t dynamic_getfullkeyid(struct onak_dbctx *dbctx, + uint64_t keyid) { - if (loaded_backend == NULL) { - load_backend(); - } - - if (loaded_backend != NULL) { - if (loaded_backend->fetch_key_skshash != NULL) { - return loaded_backend->fetch_key_skshash(hash, - publickey); - } - } + struct onak_dynamic_dbctx *privctx = + (struct onak_dynamic_dbctx *) dbctx->priv; - return -1; + return privctx->loadeddbctx->getfullkeyid(privctx->loadeddbctx, keyid); } -static int dynamic_iterate_keys(void (*iterfunc)(void *ctx, - struct openpgp_publickey *key), void *ctx) +static int dynamic_iterate_keys(struct onak_dbctx *dbctx, + void (*iterfunc)(void *ctx, struct openpgp_publickey *key), + void *ctx) { - if (loaded_backend == NULL) { - load_backend(); - } - - if (loaded_backend != NULL) { - if (loaded_backend->iterate_keys != NULL) { - return loaded_backend->iterate_keys(iterfunc, ctx); - } - } + struct onak_dynamic_dbctx *privctx = + (struct onak_dynamic_dbctx *) dbctx->priv; - return -1; + return privctx->loadeddbctx->iterate_keys(privctx->loadeddbctx, + iterfunc, ctx); } -/** - * keyid2uid - Takes a keyid and returns the primary UID for it. - * @keyid: The keyid to lookup. - */ -static char *dynamic_keyid2uid(uint64_t keyid) +static void dynamic_cleanupdb(struct onak_dbctx *dbctx) { - struct openpgp_publickey *publickey = NULL; - struct openpgp_signedpacket_list *curuid = NULL; - char buf[1024]; + struct onak_dynamic_dbctx *privctx = + (struct onak_dynamic_dbctx *) dbctx->priv; - if (loaded_backend == NULL) { - load_backend(); - } - - if (loaded_backend != NULL) { - if (loaded_backend->keyid2uid != NULL) { - return loaded_backend->keyid2uid(keyid); + if (privctx->loadeddbctx != NULL) { + if (privctx->loadeddbctx->cleanupdb != NULL) { + privctx->loadeddbctx->cleanupdb(privctx->loadeddbctx); + privctx->loadeddbctx = NULL; } } - - buf[0]=0; - if (dynamic_fetch_key_id(keyid, &publickey, false) && - publickey != NULL) { - curuid = publickey->uids; - while (curuid != NULL && buf[0] == 0) { - if (curuid->packet->tag == OPENPGP_PACKET_UID) { - snprintf(buf, 1023, "%.*s", - (int) curuid->packet->length, - curuid->packet->data); - } - curuid = curuid -> next; - } - free_publickey(publickey); - } - if (buf[0] == 0) { - return NULL; - } else { - return strdup(buf); + if (privctx->backend_handle != NULL) { + dlclose(privctx->backend_handle); + privctx->backend_handle = NULL; } -} -/** - * getkeysigs - Gets a linked list of the signatures on a key. - * @keyid: The keyid to get the sigs for. - * @revoked: Is the key revoked? - * - * This function gets the list of signatures on a key. Used for key - * indexing and doing stats bits. If revoked is non-NULL then if the key - * is revoked it's set to true. - */ -static struct ll *dynamic_getkeysigs(uint64_t keyid, bool *revoked) -{ - struct ll *sigs = NULL; - struct openpgp_signedpacket_list *uids = NULL; - struct openpgp_publickey *publickey = NULL; - - if ( loaded_backend == NULL ) { - load_backend(); - } - - if (loaded_backend != NULL) { - if (loaded_backend->getkeysigs != NULL) { - return loaded_backend->getkeysigs(keyid,revoked); - } + if (dbctx->priv != NULL) { + free(dbctx->priv); + dbctx->priv = NULL; } - dynamic_fetch_key_id(keyid, &publickey, false); - - if (publickey != NULL) { - for (uids = publickey->uids; uids != NULL; uids = uids->next) { - sigs = keysigs(sigs, uids->sigs); - } - if (revoked != NULL) { - *revoked = publickey->revoked; - } - free_publickey(publickey); + if (dbctx != NULL) { + free(dbctx); } - - return sigs; } -/** - * cached_getkeysigs - Gets the signatures on a key. - * @keyid: The key we want the signatures for. - * - * This function gets the signatures on a key. It's the same as the - * getkeysigs function above except we use the hash module to cache the - * data so if we need it again it's already loaded. - */ -static struct ll *dynamic_cached_getkeysigs(uint64_t keyid) +struct onak_dbctx *keydb_dynamic_init(bool readonly) { - struct stats_key *key = NULL; - struct stats_key *signedkey = NULL; - struct ll *cursig = NULL; - bool revoked = false; + struct onak_dbctx *dbctx; + char *soname; + char *initname; + struct onak_dbctx *(*backend_init)(bool); + struct onak_dynamic_dbctx *privctx; + + dbctx = malloc(sizeof(struct onak_dbctx)); - if (keyid == 0) { + if (dbctx == NULL) { return NULL; } - - if (loaded_backend == NULL) { - load_backend(); - } - - if (loaded_backend != NULL) { - if (loaded_backend->cached_getkeysigs != NULL) { - return loaded_backend->cached_getkeysigs(keyid); - } - } - - key = createandaddtohash(keyid); - if (key->gotsigs == false) { - key->sigs = dynamic_getkeysigs(key->keyid, &revoked); - key->revoked = revoked; - for (cursig = key->sigs; cursig != NULL; - cursig = cursig->next) { - signedkey = (struct stats_key *) cursig->object; - signedkey->signs = lladd(signedkey->signs, key); - } - key->gotsigs = true; + dbctx->priv = privctx = malloc(sizeof(struct onak_dynamic_dbctx)); + if (dbctx->priv == NULL) { + free(dbctx); + return (NULL); } - return key->sigs; -} - -/** - * 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 dynamic_getfullkeyid(uint64_t keyid) -{ - struct openpgp_publickey *publickey = NULL; - - if (loaded_backend == NULL) { - load_backend(); - } - - if (loaded_backend != NULL) { - if (loaded_backend->getfullkeyid != NULL) { - return loaded_backend->getfullkeyid(keyid); - } + if (config.use_keyd) { + free(config.db_backend); + config.db_backend = strdup("keyd"); } - if (keyid < 0x100000000LL) { - dynamic_fetch_key_id(keyid, &publickey, false); - if (publickey != NULL) { - get_keyid(publickey, &keyid); - free_publickey(publickey); - publickey = NULL; - } else { - keyid = 0; - } + if (!config.db_backend) { + logthing(LOGTHING_CRITICAL, "No database backend defined."); + exit(EXIT_FAILURE); } - - return keyid; -} -/** - * update_keys - Takes a list of public keys and updates them in the DB. - * @keys: The keys to update in the DB. - * @sendsync: Should we send a sync mail to our peers. - * - * Takes a list of keys and adds them to the database, merging them with - * the key in the database if it's already present there. The key list is - * update to contain the minimum set of updates required to get from what - * we had before to what we have now (ie the set of data that was added to - * the DB). Returns the number of entirely new keys added. - */ -static int dynamic_update_keys(struct openpgp_publickey **keys, bool sendsync) -{ - struct openpgp_publickey *curkey = NULL; - struct openpgp_publickey *oldkey = NULL; - struct openpgp_publickey *prev = NULL; - int newkeys = 0; - bool intrans; - uint64_t keyid; - - if (loaded_backend == NULL) { - load_backend(); - } - - if (loaded_backend != NULL) { - if (loaded_backend->update_keys != NULL) { - return loaded_backend->update_keys(keys, sendsync); - } - } + if (config.backends_dir == NULL) { + soname = malloc(strlen(config.db_backend) + + strlen("./libkeydb_") + + strlen(".so") + + 1); - for (curkey = *keys; curkey != NULL; curkey = curkey->next) { - intrans = dynamic_starttrans(); - get_keyid(curkey, &keyid); - logthing(LOGTHING_INFO, - "Fetching key 0x%" PRIX64 ", result: %d", - keyid, - dynamic_fetch_key_id(keyid, &oldkey, intrans)); - - /* - * If we already have the key stored in the DB then merge it - * with the new one that's been supplied. Otherwise the key - * we've just got is the one that goes in the DB and also the - * one that we send out. - */ - if (oldkey != NULL) { - merge_keys(oldkey, curkey); - if (curkey->sigs == NULL && - curkey->uids == NULL && - curkey->subkeys == NULL) { - if (prev == NULL) { - *keys = curkey->next; - } else { - prev->next = curkey->next; - curkey->next = NULL; - free_publickey(curkey); - curkey = prev; - } - } else { - prev = curkey; - logthing(LOGTHING_INFO, - "Merged key; storing updated key."); - dynamic_store_key(oldkey, intrans, true); - } - free_publickey(oldkey); - oldkey = NULL; - - } else { - logthing(LOGTHING_INFO, - "Storing completely new key."); - dynamic_store_key(curkey, intrans, false); - newkeys++; - } - dynamic_endtrans(); - intrans = false; - } + sprintf(soname, "./libkeydb_%s.so", config.db_backend); + } else { + soname = malloc(strlen(config.db_backend) + + strlen("/libkeydb_") + + strlen(".so") + + strlen(config.backends_dir) + + 1); - if (sendsync && keys != NULL) { - sendkeysync(*keys); + sprintf(soname, "%s/libkeydb_%s.so", config.backends_dir, + config.db_backend); } - return newkeys; -} + logthing(LOGTHING_INFO, "Loading dynamic backend: %s", soname); -static void dynamic_initdb(bool readonly) -{ - if (loaded_backend == NULL) { - load_backend(); + privctx->backend_handle = dlopen(soname, RTLD_LAZY); + if (privctx->backend_handle == NULL) { + logthing(LOGTHING_CRITICAL, + "Failed to open handle to library '%s': %s", + soname, dlerror()); + free(soname); + soname = NULL; + exit(EXIT_FAILURE); } - if (loaded_backend != NULL) { - if (loaded_backend->initdb != NULL) { - loaded_backend->initdb(readonly); - } - } -} + initname = malloc(strlen(config.db_backend) + + strlen("keydb_") + + strlen("_init") + + 1); + sprintf(initname, "keydb_%s_init", config.db_backend); -static void dynamic_cleanupdb(void) -{ - if (loaded_backend != NULL) { - if (loaded_backend->cleanupdb != NULL) { - loaded_backend->cleanupdb(); - } + *(void **) (&backend_init) = dlsym(privctx->backend_handle, initname); + free(initname); + + if (backend_init == NULL) { + logthing(LOGTHING_CRITICAL, + "Failed to find dbfuncs structure in library " + "'%s' : %s", soname, dlerror()); + free(soname); + soname = NULL; + exit(EXIT_FAILURE); } + free(soname); + soname = NULL; - close_backend(); + privctx->loadeddbctx = backend_init(readonly); + + if (privctx->loadeddbctx != NULL) { + dbctx->cleanupdb = dynamic_cleanupdb; + dbctx->starttrans = dynamic_starttrans; + dbctx->endtrans = dynamic_endtrans; + dbctx->fetch_key_id = dynamic_fetch_key_id; + dbctx->fetch_key_fp = dynamic_fetch_key_fp; + dbctx->fetch_key_text = dynamic_fetch_key_text; + dbctx->fetch_key_skshash = dynamic_fetch_key_skshash; + dbctx->store_key = dynamic_store_key; + dbctx->update_keys = dynamic_update_keys; + dbctx->delete_key = dynamic_delete_key; + dbctx->getkeysigs = dynamic_getkeysigs; + dbctx->cached_getkeysigs = dynamic_cached_getkeysigs; + dbctx->keyid2uid = dynamic_keyid2uid; + dbctx->getfullkeyid = dynamic_getfullkeyid; + dbctx->iterate_keys = dynamic_iterate_keys; + } + + return dbctx; } - -struct dbfuncs keydb_dynamic_funcs = { - .initdb = dynamic_initdb, - .cleanupdb = dynamic_cleanupdb, - .starttrans = dynamic_starttrans, - .endtrans = dynamic_endtrans, - .fetch_key_id = dynamic_fetch_key_id, - .fetch_key_fp = dynamic_fetch_key_fp, - .fetch_key_text = dynamic_fetch_key_text, - .fetch_key_skshash = dynamic_fetch_key_skshash, - .store_key = dynamic_store_key, - .update_keys = dynamic_update_keys, - .delete_key = dynamic_delete_key, - .getkeysigs = dynamic_getkeysigs, - .cached_getkeysigs = dynamic_cached_getkeysigs, - .keyid2uid = dynamic_keyid2uid, - .getfullkeyid = dynamic_getfullkeyid, - .iterate_keys = dynamic_iterate_keys, -}; diff --git a/keydb_file.c b/keydb_file.c index eeae01f..e0ed610 100644 --- a/keydb_file.c +++ b/keydb_file.c @@ -37,30 +37,12 @@ #include "onak-conf.h" #include "parsekey.h" -/** - * initdb - Initialize the key database. - * - * This is just a no-op for flat file access. - */ -static void file_initdb(bool readonly) -{ -} - -/** - * cleanupdb - De-initialize the key database. - * - * This is just a no-op for flat file access. - */ -static void file_cleanupdb(void) -{ -} - /** * starttrans - Start a transaction. * * This is just a no-op for flat file access. */ -static bool file_starttrans(void) +static bool file_starttrans(struct onak_dbctx *dbctx) { return true; } @@ -70,7 +52,7 @@ static bool file_starttrans(void) * * This is just a no-op for flat file access. */ -static void file_endtrans(void) +static void file_endtrans(struct onak_dbctx *dbctx) { return; } @@ -87,15 +69,17 @@ static void file_endtrans(void) * in and then parse_keys() to parse the packets into a publickey * structure. */ -static int file_fetch_key_id(uint64_t keyid, +static int file_fetch_key_id(struct onak_dbctx *dbctx, + uint64_t keyid, struct openpgp_publickey **publickey, bool intrans) { + char *db_dir = (char *) dbctx->priv; struct openpgp_packet_list *packets = NULL; char keyfile[1024]; int fd = -1; - snprintf(keyfile, 1023, "%s/0x%" PRIX64, config.db_dir, + snprintf(keyfile, 1023, "%s/0x%" PRIX64, db_dir, keyid & 0xFFFFFFFF); fd = open(keyfile, O_RDONLY); // | O_SHLOCK); @@ -121,9 +105,11 @@ static int file_fetch_key_id(uint64_t keyid, * packets and then use write_openpgp_stream() to write the stream out to * the file. */ -static int file_store_key(struct openpgp_publickey *publickey, bool intrans, +static int file_store_key(struct onak_dbctx *dbctx, + struct openpgp_publickey *publickey, bool intrans, bool update) { + char *db_dir = (char *) dbctx->priv; struct openpgp_packet_list *packets = NULL; struct openpgp_packet_list *list_end = NULL; struct openpgp_publickey *next = NULL; @@ -135,7 +121,7 @@ static int file_store_key(struct openpgp_publickey *publickey, bool intrans, logthing(LOGTHING_ERROR, "Couldn't find key ID for key."); return 0; } - snprintf(keyfile, 1023, "%s/0x%" PRIX64, config.db_dir, + snprintf(keyfile, 1023, "%s/0x%" PRIX64, db_dir, keyid & 0xFFFFFFFF); fd = open(keyfile, O_WRONLY | O_CREAT, 0664); // | O_EXLOCK); @@ -162,11 +148,13 @@ static int file_store_key(struct openpgp_publickey *publickey, bool intrans, * This function deletes a public key from whatever storage mechanism we * are using. Returns 0 if the key existed. */ -static int file_delete_key(uint64_t keyid, bool intrans) +static int file_delete_key(struct onak_dbctx *dbctx, + uint64_t keyid, bool intrans) { + char *db_dir = (char *) dbctx->priv; char keyfile[1024]; - snprintf(keyfile, 1023, "%s/0x%" PRIX64, config.db_dir, + snprintf(keyfile, 1023, "%s/0x%" PRIX64, db_dir, keyid & 0xFFFFFFFF); return unlink(keyfile); @@ -182,7 +170,8 @@ static int file_delete_key(uint64_t keyid, bool intrans) * * TODO: Write for flat file access. Some sort of grep? */ -static int file_fetch_key_text(const char *search, +static int file_fetch_key_text(struct onak_dbctx *dbctx, + const char *search, struct openpgp_publickey **publickey) { return 0; @@ -199,9 +188,11 @@ static int file_fetch_key_text(const char *search, * * Returns the number of keys we iterated over. */ -static int file_iterate_keys(void (*iterfunc)(void *ctx, - struct openpgp_publickey *key), void *ctx) +static int file_iterate_keys(struct onak_dbctx *dbctx, + void (*iterfunc)(void *ctx, struct openpgp_publickey *key), + void *ctx) { + char *db_dir = (char *) dbctx->priv; int numkeys = 0; struct openpgp_packet_list *packets = NULL; struct openpgp_publickey *key = NULL; @@ -210,14 +201,14 @@ static int file_iterate_keys(void (*iterfunc)(void *ctx, int fd = -1; struct dirent *curfile = NULL; - dir = opendir(config.db_dir); + dir = opendir(db_dir); if (dir != NULL) { while ((curfile = readdir(dir)) != NULL) { if (curfile->d_name[0] == '0' && curfile->d_name[1] == 'x') { snprintf(keyfile, 1023, "%s/%s", - config.db_dir, + db_dir, curfile->d_name); fd = open(keyfile, O_RDONLY); @@ -257,20 +248,53 @@ static int file_iterate_keys(void (*iterfunc)(void *ctx, #define NEED_GET_FP 1 #include "keydb.c" -struct dbfuncs keydb_file_funcs = { - .initdb = file_initdb, - .cleanupdb = file_cleanupdb, - .starttrans = file_starttrans, - .endtrans = file_endtrans, - .fetch_key_id = file_fetch_key_id, - .fetch_key_fp = generic_fetch_key_fp, - .fetch_key_text = file_fetch_key_text, - .store_key = file_store_key, - .update_keys = generic_update_keys, - .delete_key = file_delete_key, - .getkeysigs = generic_getkeysigs, - .cached_getkeysigs = generic_cached_getkeysigs, - .keyid2uid = generic_keyid2uid, - .getfullkeyid = generic_getfullkeyid, - .iterate_keys = file_iterate_keys, -}; +/** + * cleanupdb - De-initialize the key database. + * + * This is just a no-op for flat file access. + */ +static void file_cleanupdb(struct onak_dbctx *dbctx) +{ + if (dbctx->priv != NULL) { + free(dbctx->priv); + dbctx->priv = NULL; + } + + if (dbctx != NULL) { + free(dbctx); + } +} + +/** + * initdb - Initialize the key database. + * + * This is just a no-op for flat file access. + */ +struct onak_dbctx *keydb_file_init(bool readonly) +{ + struct onak_dbctx *dbctx; + + dbctx = malloc(sizeof(struct onak_dbctx)); + if (dbctx == NULL) { + return NULL; + } + + dbctx->priv = strdup(config.db_dir); + + dbctx->cleanupdb = file_cleanupdb; + dbctx->starttrans = file_starttrans; + dbctx->endtrans = file_endtrans; + dbctx->fetch_key_id = file_fetch_key_id; + dbctx->fetch_key_fp = generic_fetch_key_fp; + dbctx->fetch_key_text = file_fetch_key_text; + dbctx->store_key = file_store_key; + dbctx->update_keys = generic_update_keys; + dbctx->delete_key = file_delete_key; + dbctx->getkeysigs = generic_getkeysigs; + dbctx->cached_getkeysigs = generic_cached_getkeysigs; + dbctx->keyid2uid = generic_keyid2uid; + dbctx->getfullkeyid = generic_getfullkeyid; + dbctx->iterate_keys = file_iterate_keys; + + return dbctx; +} diff --git a/keydb_fs.c b/keydb_fs.c index b944732..9e072ba 100644 --- a/keydb_fs.c +++ b/keydb_fs.c @@ -46,8 +46,10 @@ #define PATH_MAX 1024 #endif -static int keydb_lockfile_fd = -1; -static bool keydb_lockfile_readonly; +struct onak_fs_dbctx { + int lockfile_fd; + bool lockfile_readonly; +}; /*****************************************************************************/ @@ -161,65 +163,21 @@ static void subkeydir(char *buffer, size_t length, uint64_t subkey) /*****************************************************************************/ -/** - * initdb - Initialize the key database. - */ -static void fs_initdb(bool readonly) -{ - char buffer[PATH_MAX]; - - keydb_lockfile_readonly = readonly; - - snprintf(buffer, sizeof(buffer), "%s/.lock", config.db_dir); - - if (access(config.db_dir, R_OK | W_OK | X_OK) == -1) { - if (errno != ENOENT) { - logthing(LOGTHING_CRITICAL, - "Unable to access keydb_fs root of '%s'. (%s)", - config.db_dir, strerror(errno)); - exit(1); /* Lacking rwx on the key dir */ - } - mkdir(config.db_dir, 0777); - keydb_lockfile_fd = open(buffer, O_RDWR | O_CREAT, 0600); - } - chdir(config.db_dir); - if (keydb_lockfile_fd == -1) - keydb_lockfile_fd = open(buffer, - (keydb_lockfile_readonly) ? - O_RDONLY : O_RDWR); - if (keydb_lockfile_fd == -1) - keydb_lockfile_fd = open(buffer, O_RDWR | O_CREAT, 0600); - if (keydb_lockfile_fd == -1) { - logthing(LOGTHING_CRITICAL, - "Unable to open lockfile '%s'. (%s)", - buffer, strerror(errno)); - exit(1); /* Lacking rwx on the key dir */ - } -} - -/** - * cleanupdb - De-initialize the key database. - */ -static void fs_cleanupdb(void) -{ - /* Mmmm nothing to do here? */ - close(keydb_lockfile_fd); -} - /** * starttrans - Start a transaction. */ -static bool fs_starttrans(void) +static bool fs_starttrans(struct onak_dbctx *dbctx) { + struct onak_fs_dbctx *privctx = (struct onak_fs_dbctx *) dbctx->priv; struct flock lockstruct; int remaining = 20; lockstruct.l_type = - F_RDLCK | ((keydb_lockfile_readonly) ? 0 : F_WRLCK); + F_RDLCK | ((privctx->lockfile_readonly) ? 0 : F_WRLCK); lockstruct.l_whence = SEEK_SET; lockstruct.l_start = 0; lockstruct.l_len = 1; - while (fcntl(keydb_lockfile_fd, F_SETLK, &lockstruct) == -1) { + while (fcntl(privctx->lockfile_fd, F_SETLK, &lockstruct) == -1) { if (remaining-- == 0) return false; /* Hope to hell that noodles DTRT */ usleep(100); @@ -230,18 +188,19 @@ static bool fs_starttrans(void) /** * endtrans - End a transaction. */ -static void fs_endtrans(void) +static void fs_endtrans(struct onak_dbctx *dbctx) { + struct onak_fs_dbctx *privctx = (struct onak_fs_dbctx *) dbctx->priv; struct flock lockstruct; lockstruct.l_type = F_UNLCK; lockstruct.l_whence = SEEK_SET; lockstruct.l_start = 0; lockstruct.l_len = 1; - fcntl(keydb_lockfile_fd, F_SETLK, &lockstruct); + fcntl(privctx->lockfile_fd, F_SETLK, &lockstruct); } -static uint64_t fs_getfullkeyid(uint64_t keyid) +static uint64_t fs_getfullkeyid(struct onak_dbctx *dbctx, uint64_t keyid) { static char buffer[PATH_MAX]; DIR *d = NULL; @@ -285,7 +244,8 @@ static uint64_t fs_getfullkeyid(uint64_t keyid) * @publickey: A pointer to a structure to return the key in. * @intrans: If we're already in a transaction. */ -static int fs_fetch_key_id(uint64_t keyid, +static int fs_fetch_key_id(struct onak_dbctx *dbctx, + uint64_t keyid, struct openpgp_publickey **publickey, bool intrans) { @@ -294,10 +254,10 @@ static int fs_fetch_key_id(uint64_t keyid, struct openpgp_packet_list *packets = NULL; if (!intrans) - fs_starttrans(); + fs_starttrans(dbctx); if ((keyid >> 32) == 0) - keyid = fs_getfullkeyid(keyid); + keyid = fs_getfullkeyid(dbctx, keyid); keypath(buffer, sizeof(buffer), keyid); if ((fd = open(buffer, O_RDONLY)) != -1) { @@ -311,7 +271,7 @@ static int fs_fetch_key_id(uint64_t keyid, } if (!intrans) - fs_endtrans(); + fs_endtrans(dbctx); return ret; } @@ -321,7 +281,8 @@ static int fs_fetch_key_id(uint64_t keyid, * @intrans: If we're already in a transaction. * @update: If true the key exists and should be updated. */ -static int fs_store_key(struct openpgp_publickey *publickey, bool intrans, +static int fs_store_key(struct onak_dbctx *dbctx, + struct openpgp_publickey *publickey, bool intrans, bool update) { static char buffer[PATH_MAX]; @@ -343,7 +304,7 @@ static int fs_store_key(struct openpgp_publickey *publickey, bool intrans, } if (!intrans) - fs_starttrans(); + fs_starttrans(dbctx); prove_path_to(keyid, "key"); keypath(buffer, sizeof(buffer), keyid); @@ -406,7 +367,7 @@ static int fs_store_key(struct openpgp_publickey *publickey, bool intrans, } if (!intrans) - fs_endtrans(); + fs_endtrans(dbctx); return ret; } @@ -415,7 +376,7 @@ static int fs_store_key(struct openpgp_publickey *publickey, bool intrans, * @keyid: The keyid to delete. * @intrans: If we're already in a transaction. */ -static int fs_delete_key(uint64_t keyid, bool intrans) +static int fs_delete_key(struct onak_dbctx *dbctx, uint64_t keyid, bool intrans) { static char buffer[PATH_MAX]; int ret; @@ -426,12 +387,12 @@ static int fs_delete_key(uint64_t keyid, bool intrans) int i = 0; if ((keyid >> 32) == 0) - keyid = fs_getfullkeyid(keyid); + keyid = fs_getfullkeyid(dbctx, keyid); if (!intrans) - fs_starttrans(); + fs_starttrans(dbctx); - ret = fs_fetch_key_id(keyid, &pk, true); + ret = fs_fetch_key_id(dbctx, keyid, &pk, true); if (ret) { logthing(LOGTHING_DEBUG, "Wordlist for key %016" PRIX64, @@ -475,7 +436,7 @@ static int fs_delete_key(uint64_t keyid, bool intrans) unlink(buffer); if (!intrans) - fs_endtrans(); + fs_endtrans(dbctx); return 1; } @@ -519,7 +480,8 @@ static struct ll *internal_get_key_by_word(char *word, struct ll *mct) * @search: The text to search for. * @publickey: A pointer to a structure to return the key in. */ -static int fs_fetch_key_text(const char *search, +static int fs_fetch_key_text(struct onak_dbctx *dbctx, + const char *search, struct openpgp_publickey **publickey) { struct ll *wordlist = NULL, *wl = NULL; @@ -564,7 +526,8 @@ static int fs_fetch_key_text(const char *search, while (wl) { logthing(LOGTHING_DEBUG, "Adding key: %s", wl->object); addedkeys += - fs_fetch_key_id(strtoull(wl->object, NULL, 16), publickey, + fs_fetch_key_id(dbctx, + strtoull(wl->object, NULL, 16), publickey, false); if (addedkeys >= config.maxkeys) break; @@ -584,7 +547,8 @@ static int fs_fetch_key_text(const char *search, * @publickey: A pointer to a structure to return the key in. * @intrans: If we're already in a transaction. */ -static int fs_fetch_key_skshash(const struct skshash *hash, +static int fs_fetch_key_skshash(struct onak_dbctx *dbctx, + const struct skshash *hash, struct openpgp_publickey **publickey) { static char buffer[PATH_MAX]; @@ -615,7 +579,8 @@ static int fs_fetch_key_skshash(const struct skshash *hash, * * Returns the number of keys we iterated over. */ -static int fs_iterate_keys(void (*iterfunc)(void *ctx, +static int fs_iterate_keys(struct onak_dbctx *dbctx, + void (*iterfunc)(void *ctx, struct openpgp_publickey *key), void *ctx) { return 0; @@ -630,21 +595,79 @@ static int fs_iterate_keys(void (*iterfunc)(void *ctx, #define NEED_GET_FP 1 #include "keydb.c" -struct dbfuncs keydb_fs_funcs = { - .initdb = fs_initdb, - .cleanupdb = fs_cleanupdb, - .starttrans = fs_starttrans, - .endtrans = fs_endtrans, - .fetch_key_id = fs_fetch_key_id, - .fetch_key_fp = generic_fetch_key_fp, - .fetch_key_text = fs_fetch_key_text, - .fetch_key_skshash = fs_fetch_key_skshash, - .store_key = fs_store_key, - .update_keys = generic_update_keys, - .delete_key = fs_delete_key, - .getkeysigs = generic_getkeysigs, - .cached_getkeysigs = generic_cached_getkeysigs, - .keyid2uid = generic_keyid2uid, - .getfullkeyid = fs_getfullkeyid, - .iterate_keys = fs_iterate_keys, -}; +/** + * cleanupdb - De-initialize the key database. + */ +static void fs_cleanupdb(struct onak_dbctx *dbctx) +{ + struct onak_fs_dbctx *privctx = (struct onak_fs_dbctx *) dbctx->priv; + + /* Mmmm nothing to do here? */ + close(privctx->lockfile_fd); +} + +/** + * initdb - Initialize the key database. + */ +struct onak_dbctx *keydb_fs_init(bool readonly) +{ + char buffer[PATH_MAX]; + struct onak_dbctx *dbctx; + struct onak_fs_dbctx *privctx; + + dbctx = malloc(sizeof(struct onak_dbctx)); + if (dbctx == NULL) { + return NULL; + } + dbctx->priv = privctx = malloc(sizeof(*privctx)); + if (privctx == NULL) { + free(dbctx); + return NULL; + } + + privctx->lockfile_readonly = readonly; + + snprintf(buffer, sizeof(buffer), "%s/.lock", config.db_dir); + + if (access(config.db_dir, R_OK | W_OK | X_OK) == -1) { + if (errno != ENOENT) { + logthing(LOGTHING_CRITICAL, + "Unable to access keydb_fs root of '%s'. (%s)", + config.db_dir, strerror(errno)); + exit(1); /* Lacking rwx on the key dir */ + } + mkdir(config.db_dir, 0777); + privctx->lockfile_fd = open(buffer, O_RDWR | O_CREAT, 0600); + } + chdir(config.db_dir); + if (privctx->lockfile_fd == -1) + privctx->lockfile_fd = open(buffer, + (privctx->lockfile_readonly) ? + O_RDONLY : O_RDWR); + if (privctx->lockfile_fd == -1) + privctx->lockfile_fd = open(buffer, O_RDWR | O_CREAT, 0600); + if (privctx->lockfile_fd == -1) { + logthing(LOGTHING_CRITICAL, + "Unable to open lockfile '%s'. (%s)", + buffer, strerror(errno)); + exit(1); /* Lacking rwx on the key dir */ + } + + dbctx->cleanupdb = fs_cleanupdb; + dbctx->starttrans = fs_starttrans; + dbctx->endtrans = fs_endtrans; + dbctx->fetch_key_id = fs_fetch_key_id; + dbctx->fetch_key_fp = generic_fetch_key_fp; + dbctx->fetch_key_text = fs_fetch_key_text; + dbctx->fetch_key_skshash = fs_fetch_key_skshash; + dbctx->store_key = fs_store_key; + dbctx->update_keys = generic_update_keys; + dbctx->delete_key = fs_delete_key; + dbctx->getkeysigs = generic_getkeysigs; + dbctx->cached_getkeysigs = generic_cached_getkeysigs; + dbctx->keyid2uid = generic_keyid2uid; + dbctx->getfullkeyid = fs_getfullkeyid; + dbctx->iterate_keys = fs_iterate_keys; + + return dbctx; +} diff --git a/keydb_hkp.c b/keydb_hkp.c index 3fa1593..7c7b31a 100644 --- a/keydb_hkp.c +++ b/keydb_hkp.c @@ -33,11 +33,12 @@ #include "parsekey.h" #include "version.h" -static CURL *curl = NULL; - -static char hkpbase[1024]; +struct onak_hkp_dbctx { + CURL *curl; + char hkpbase[1024]; +}; -static int hkp_parse_url(const char *url) +static int hkp_parse_url(struct onak_hkp_dbctx *privctx, const char *url) { char proto[6], host[256]; unsigned int port; @@ -65,13 +66,13 @@ static int hkp_parse_url(const char *url) if (port == 0) { port = 11371; } - snprintf(hkpbase, sizeof(hkpbase), + snprintf(privctx->hkpbase, sizeof(privctx->hkpbase), "http://%s:%u/pks", host, port); } else if (!strcmp(proto, "hkps")) { if (port == 0) { port = 11372; } - snprintf(hkpbase, sizeof(hkpbase), + snprintf(privctx->hkpbase, sizeof(privctx->hkpbase), "https://%s:%u/pks", host, port); } else if (strcmp(proto, "http") && strcmp(proto, "https")) { logthing(LOGTHING_CRITICAL, "Unknown HKP protocol: %s", @@ -79,10 +80,10 @@ static int hkp_parse_url(const char *url) ret = 0; goto out; } else if (port == 0) { - snprintf(hkpbase, sizeof(hkpbase), + snprintf(privctx->hkpbase, sizeof(privctx->hkpbase), "%s://%s/pks", proto, host); } else { - snprintf(hkpbase, sizeof(hkpbase), + snprintf(privctx->hkpbase, sizeof(privctx->hkpbase), "%s://%s:%u/pks", proto, host, port); } @@ -90,52 +91,6 @@ out: return ret; } -/** - * cleanupdb - De-initialize the key database. - * - * We cleanup CURL here. - */ -static void hkp_cleanupdb(void) -{ - if (curl) { - curl_easy_cleanup(curl); - curl = NULL; - } - curl_global_cleanup(); -} - -/** - * initdb - Initialize the key database. - * - * We initialize CURL here. - */ -static void hkp_initdb(bool readonly) -{ - curl_version_info_data *curl_info; - - if (!hkp_parse_url(config.db_dir)) { - exit(EXIT_FAILURE); - } - curl_global_init(CURL_GLOBAL_DEFAULT); - curl = curl_easy_init(); - if (curl == NULL) { - logthing(LOGTHING_CRITICAL, "Could not initialize CURL."); - exit(EXIT_FAILURE); - } - curl_easy_setopt(curl, CURLOPT_USERAGENT, "onak/" ONAK_VERSION); - - if (strncmp(hkpbase, "https://", 8) == 0) { - curl_info = curl_version_info(CURLVERSION_NOW); - if (! (curl_info->features & CURL_VERSION_SSL)) { - logthing(LOGTHING_CRITICAL, - "CURL lacks SSL support; cannot use HKP url: %s", - hkpbase); - hkp_cleanupdb(); - exit(EXIT_FAILURE); - } - } -} - /** * Receive data from a CURL request and process it into a buffer context. */ @@ -147,10 +102,12 @@ static size_t hkp_curl_recv_data(void *buffer, size_t size, size_t nmemb, return (nmemb * size); } -static int hkp_fetch_key_url(char *url, +static int hkp_fetch_key_url(struct onak_dbctx *dbctx, + char *url, struct openpgp_publickey **publickey, bool intrans) { + struct onak_hkp_dbctx *privctx = (struct onak_hkp_dbctx *) dbctx->priv; struct openpgp_packet_list *packets = NULL; CURLcode res; struct buffer_ctx buf; @@ -160,11 +117,11 @@ static int hkp_fetch_key_url(char *url, buf.size = 8192; buf.buffer = malloc(8192); - curl_easy_setopt(curl, CURLOPT_URL, url); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, + curl_easy_setopt(privctx->curl, CURLOPT_URL, url); + curl_easy_setopt(privctx->curl, CURLOPT_WRITEFUNCTION, hkp_curl_recv_data); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buf); - res = curl_easy_perform(curl); + curl_easy_setopt(privctx->curl, CURLOPT_WRITEDATA, &buf); + res = curl_easy_perform(privctx->curl); if (res == 0) { buf.offset = 0; @@ -187,26 +144,30 @@ static int hkp_fetch_key_url(char *url, /** * hkp_fetch_key_id - Given a keyid fetch the key from HKP server. */ -static int hkp_fetch_key_id(uint64_t keyid, +static int hkp_fetch_key_id(struct onak_dbctx *dbctx, + uint64_t keyid, struct openpgp_publickey **publickey, bool intrans) { + struct onak_hkp_dbctx *privctx = (struct onak_hkp_dbctx *) dbctx->priv; char keyurl[1024]; snprintf(keyurl, sizeof(keyurl), "%s/lookup?op=get&search=0x%08" PRIX64, - hkpbase, keyid); + privctx->hkpbase, keyid); - return (hkp_fetch_key_url(keyurl, publickey, intrans)); + return (hkp_fetch_key_url(dbctx, keyurl, publickey, intrans)); } /** * hkp_fetch_key_fp - Given a fingerprint fetch the key from HKP server. */ -static int hkp_fetch_key_fp(uint8_t *fp, size_t fpsize, +static int hkp_fetch_key_fp(struct onak_dbctx *dbctx, + uint8_t *fp, size_t fpsize, struct openpgp_publickey **publickey, bool intrans) { + struct onak_hkp_dbctx *privctx = (struct onak_hkp_dbctx *) dbctx->priv; char keyurl[1024]; int i, ofs; @@ -215,7 +176,7 @@ static int hkp_fetch_key_fp(uint8_t *fp, size_t fpsize, } ofs = snprintf(keyurl, sizeof(keyurl), - "%s/lookup?op=get&search=0x", hkpbase); + "%s/lookup?op=get&search=0x", privctx->hkpbase); if ((ofs + fpsize * 2 + 1)> sizeof(keyurl)) { return 0; @@ -225,7 +186,7 @@ static int hkp_fetch_key_fp(uint8_t *fp, size_t fpsize, ofs += sprintf(&keyurl[ofs], "%02X", fp[i]); } - return (hkp_fetch_key_url(keyurl, publickey, intrans)); + return (hkp_fetch_key_url(dbctx, keyurl, publickey, intrans)); } /** @@ -238,16 +199,18 @@ static int hkp_fetch_key_fp(uint8_t *fp, size_t fpsize, * * TODO: Write for flat file access. Some sort of grep? */ -static int hkp_fetch_key_text(const char *search, +static int hkp_fetch_key_text(struct onak_dbctx *dbctx, + const char *search, struct openpgp_publickey **publickey) { + struct onak_hkp_dbctx *privctx = (struct onak_hkp_dbctx *) dbctx->priv; char keyurl[1024]; snprintf(keyurl, sizeof(keyurl), "%s/lookup?op=get&search=%s", - hkpbase, search); + privctx->hkpbase, search); - return (hkp_fetch_key_url(keyurl, publickey, false)); + return (hkp_fetch_key_url(dbctx, keyurl, publickey, false)); } /** @@ -257,9 +220,11 @@ static int hkp_fetch_key_text(const char *search, * @update: If true the key exists and should be updated. * */ -static int hkp_store_key(struct openpgp_publickey *publickey, bool intrans, +static int hkp_store_key(struct onak_dbctx *dbctx, + struct openpgp_publickey *publickey, bool intrans, bool update) { + struct onak_hkp_dbctx *privctx = (struct onak_hkp_dbctx *) dbctx->priv; struct openpgp_packet_list *packets = NULL; struct openpgp_packet_list *list_end = NULL; char keyurl[1024]; @@ -274,18 +239,18 @@ static int hkp_store_key(struct openpgp_publickey *publickey, bool intrans, flatten_publickey(publickey, &packets, &list_end); armor_openpgp_stream(buffer_putchar, &buf, packets); - addform = curl_easy_escape(curl, buf.buffer, buf.offset); + addform = curl_easy_escape(privctx->curl, buf.buffer, buf.offset); addform[7] = '='; - snprintf(keyurl, sizeof(keyurl), "%s/add", hkpbase); + snprintf(keyurl, sizeof(keyurl), "%s/add", privctx->hkpbase); - curl_easy_setopt(curl, CURLOPT_URL, keyurl); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, addform); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, + curl_easy_setopt(privctx->curl, CURLOPT_URL, keyurl); + curl_easy_setopt(privctx->curl, CURLOPT_POSTFIELDS, addform); + curl_easy_setopt(privctx->curl, CURLOPT_WRITEFUNCTION, hkp_curl_recv_data); buf.offset = 0; - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buf); - res = curl_easy_perform(curl); + curl_easy_setopt(privctx->curl, CURLOPT_WRITEDATA, &buf); + res = curl_easy_perform(privctx->curl); if (res != 0) { logthing(LOGTHING_ERROR, "Couldn't send key: %s (%d)", @@ -309,7 +274,8 @@ static int hkp_store_key(struct openpgp_publickey *publickey, bool intrans, * * No op for HKP. */ -static int hkp_delete_key(uint64_t keyid, bool intrans) +static int hkp_delete_key(struct onak_dbctx *dbctx, + uint64_t keyid, bool intrans) { return -1; } @@ -321,8 +287,9 @@ static int hkp_delete_key(uint64_t keyid, bool intrans) * * Not applicable for HKP backend. */ -static int hkp_iterate_keys(void (*iterfunc)(void *ctx, - struct openpgp_publickey *key), void *ctx) +static int hkp_iterate_keys(struct onak_dbctx *dbctx, + void (*iterfunc)(void *ctx, struct openpgp_publickey *key), + void *ctx) { return 0; } @@ -332,7 +299,7 @@ static int hkp_iterate_keys(void (*iterfunc)(void *ctx, * * This is just a no-op for HKP access. */ -static bool hkp_starttrans(void) +static bool hkp_starttrans(struct onak_dbctx *dbctx) { return true; } @@ -342,7 +309,7 @@ static bool hkp_starttrans(void) * * This is just a no-op for HKP access. */ -static void hkp_endtrans(void) +static void hkp_endtrans(struct onak_dbctx *dbctx) { return; } @@ -356,20 +323,81 @@ static void hkp_endtrans(void) #define NEED_UPDATEKEYS 1 #include "keydb.c" -struct dbfuncs keydb_hkp_funcs = { - .initdb = hkp_initdb, - .cleanupdb = hkp_cleanupdb, - .starttrans = hkp_starttrans, - .endtrans = hkp_endtrans, - .fetch_key_id = hkp_fetch_key_id, - .fetch_key_fp = hkp_fetch_key_fp, - .fetch_key_text = hkp_fetch_key_text, - .store_key = hkp_store_key, - .update_keys = generic_update_keys, - .delete_key = hkp_delete_key, - .getkeysigs = generic_getkeysigs, - .cached_getkeysigs = generic_cached_getkeysigs, - .keyid2uid = generic_keyid2uid, - .getfullkeyid = generic_getfullkeyid, - .iterate_keys = hkp_iterate_keys, -}; +/** + * cleanupdb - De-initialize the key database. + * + * We cleanup CURL here. + */ +static void hkp_cleanupdb(struct onak_dbctx *dbctx) +{ + struct onak_hkp_dbctx *privctx = (struct onak_hkp_dbctx *) dbctx->priv; + + if (privctx->curl) { + curl_easy_cleanup(privctx->curl); + privctx->curl = NULL; + } + curl_global_cleanup(); + free(privctx); + free(dbctx); +} + +/** + * initdb - Initialize the key database. + * + * We initialize CURL here. + */ +struct onak_dbctx *keydb_hkp_init(bool readonly) +{ + struct onak_dbctx *dbctx; + struct onak_hkp_dbctx *privctx; + curl_version_info_data *curl_info; + + dbctx = malloc(sizeof(struct onak_dbctx)); + if (dbctx == NULL) { + return NULL; + } + + dbctx->priv = privctx = malloc(sizeof(*privctx)); + dbctx->cleanupdb = hkp_cleanupdb; + dbctx->starttrans = hkp_starttrans; + dbctx->endtrans = hkp_endtrans; + dbctx->fetch_key_id = hkp_fetch_key_id; + dbctx->fetch_key_fp = hkp_fetch_key_fp; + dbctx->fetch_key_text = hkp_fetch_key_text; + dbctx->store_key = hkp_store_key; + dbctx->update_keys = generic_update_keys; + dbctx->delete_key = hkp_delete_key; + dbctx->getkeysigs = generic_getkeysigs; + dbctx->cached_getkeysigs = generic_cached_getkeysigs; + dbctx->keyid2uid = generic_keyid2uid; + dbctx->getfullkeyid = generic_getfullkeyid; + dbctx->iterate_keys = hkp_iterate_keys; + + if (!hkp_parse_url(privctx, config.db_dir)) { + exit(EXIT_FAILURE); + } + curl_global_init(CURL_GLOBAL_DEFAULT); + privctx->curl = curl_easy_init(); + if (privctx->curl == NULL) { + logthing(LOGTHING_CRITICAL, "Could not initialize CURL."); + hkp_cleanupdb(dbctx); + dbctx = NULL; + exit(EXIT_FAILURE); + } + curl_easy_setopt(privctx->curl, CURLOPT_USERAGENT, + "onak/" ONAK_VERSION); + + if (strncmp(privctx->hkpbase, "https://", 8) == 0) { + curl_info = curl_version_info(CURLVERSION_NOW); + if (! (curl_info->features & CURL_VERSION_SSL)) { + logthing(LOGTHING_CRITICAL, + "CURL lacks SSL support; cannot use HKP url: %s", + privctx->hkpbase); + hkp_cleanupdb(dbctx); + dbctx = NULL; + exit(EXIT_FAILURE); + } + } + + return dbctx; +} diff --git a/keydb_keyd.c b/keydb_keyd.c index 7995e38..5fd0843 100644 --- a/keydb_keyd.c +++ b/keydb_keyd.c @@ -37,123 +37,6 @@ #include "onak-conf.h" #include "parsekey.h" -/** - * keyd_fd - our file descriptor for the socket connection to keyd. - */ -static int keyd_fd = -1; - -/** - * initdb - Initialize the key database. - * @readonly: If we'll only be reading the DB, not writing to it. - * - * This function should be called before any of the other functions in - * this file are called in order to allow the DB to be initialized ready - * for access. - */ -static void keyd_initdb(bool readonly) -{ - struct sockaddr_un sock; - uint32_t cmd = KEYD_CMD_UNKNOWN; - uint32_t reply = KEYD_REPLY_UNKNOWN_CMD; - ssize_t count; - - keyd_fd = socket(PF_UNIX, SOCK_STREAM, 0); - if (keyd_fd < 0) { - logthing(LOGTHING_CRITICAL, - "Couldn't open socket: %s (%d)", - strerror(errno), - errno); - exit(EXIT_FAILURE); - } - - sock.sun_family = AF_UNIX; - snprintf(sock.sun_path, sizeof(sock.sun_path) - 1, "%s/%s", - config.db_dir, - KEYD_SOCKET); - if (connect(keyd_fd, (struct sockaddr *) &sock, sizeof(sock)) < 0) { - logthing(LOGTHING_CRITICAL, - "Couldn't connect to socket %s: %s (%d)", - sock.sun_path, - strerror(errno), - errno); - exit(EXIT_FAILURE); - } - - cmd = KEYD_CMD_VERSION; - if (write(keyd_fd, &cmd, sizeof(cmd)) != sizeof(cmd)) { - logthing(LOGTHING_CRITICAL, - "Couldn't write version cmd: %s (%d)", - strerror(errno), - errno); - } else { - count = read(keyd_fd, &reply, sizeof(reply)); - if (count == sizeof(reply) && reply == KEYD_REPLY_OK) { - count = read(keyd_fd, &reply, sizeof(reply)); - if (count != sizeof(reply) || reply != sizeof(reply)) { - logthing(LOGTHING_CRITICAL, - "Error! Unexpected keyd version " - "length: %d != %d", - reply, sizeof(reply)); - exit(EXIT_FAILURE); - } - - count = read(keyd_fd, &reply, sizeof(reply)); - logthing(LOGTHING_DEBUG, - "keyd protocol version %d", - reply); - if (reply != keyd_version) { - logthing(LOGTHING_CRITICAL, - "Error! keyd protocol version " - "mismatch. (us = %d, it = %d)", - keyd_version, reply); - } - } - } - - return; -} - -/** - * cleanupdb - De-initialize the key database. - * - * This function should be called upon program exit to allow the DB to - * cleanup after itself. - */ -static void keyd_cleanupdb(void) -{ - uint32_t cmd = KEYD_CMD_CLOSE; - - if (write(keyd_fd, &cmd, sizeof(cmd)) != sizeof(cmd)) { - logthing(LOGTHING_CRITICAL, - "Couldn't send close cmd: %s (%d)", - strerror(errno), - errno); - } - - if (read(keyd_fd, &cmd, sizeof(cmd)) != sizeof(cmd)) { - logthing(LOGTHING_CRITICAL, - "Couldn't read close cmd reply: %s (%d)", - strerror(errno), - errno); - } else if (cmd != KEYD_REPLY_OK) { - logthing(LOGTHING_CRITICAL, - "Got bad reply to KEYD_CMD_CLOSE: %d", cmd); - } - - if (shutdown(keyd_fd, SHUT_RDWR) < 0) { - logthing(LOGTHING_NOTICE, "Error shutting down socket: %d", - errno); - } - if (close(keyd_fd) < 0) { - logthing(LOGTHING_NOTICE, "Error closing down socket: %d", - errno); - } - keyd_fd = -1; - - return; -} - - /** * starttrans - Start a transaction. * @@ -161,7 +44,7 @@ static void keyd_cleanupdb(void) * operations on the database to help speed it all up, or if we want * something to only succeed if all relevant operations are successful. */ -static bool keyd_starttrans(void) +static bool keyd_starttrans(struct onak_dbctx *dbctx) { return true; } @@ -171,7 +54,7 @@ static bool keyd_starttrans(void) * * Ends a transaction. */ -static void keyd_endtrans(void) +static void keyd_endtrans(struct onak_dbctx *dbctx) { return; } @@ -187,10 +70,12 @@ static void keyd_endtrans(void) * * TODO: What about keyid collisions? Should we use fingerprint instead? */ -static int keyd_fetch_key_id(uint64_t keyid, +static int keyd_fetch_key_id(struct onak_dbctx *dbctx, + uint64_t keyid, struct openpgp_publickey **publickey, bool intrans) { + int keyd_fd = (intptr_t) dbctx->priv; struct buffer_ctx keybuf; struct openpgp_packet_list *packets = NULL; uint32_t cmd = KEYD_CMD_GET_ID; @@ -230,10 +115,12 @@ static int keyd_fetch_key_id(uint64_t keyid, return (count > 0) ? 1 : 0; } -static int keyd_fetch_key_fp(uint8_t *fp, size_t fpsize, +static int keyd_fetch_key_fp(struct onak_dbctx *dbctx, + uint8_t *fp, size_t fpsize, struct openpgp_publickey **publickey, bool intrans) { + int keyd_fd = (intptr_t) dbctx->priv; struct buffer_ctx keybuf; struct openpgp_packet_list *packets = NULL; uint32_t cmd = KEYD_CMD_GET_FP; @@ -288,8 +175,10 @@ static int keyd_fetch_key_fp(uint8_t *fp, size_t fpsize, * This function deletes a public key from whatever storage mechanism we * are using. Returns 0 if the key existed. */ -static int keyd_delete_key(uint64_t keyid, bool intrans) +static int keyd_delete_key(struct onak_dbctx *dbctx, + uint64_t keyid, bool intrans) { + int keyd_fd = (intptr_t) dbctx->priv; uint32_t cmd = KEYD_CMD_DELETE; write(keyd_fd, &cmd, sizeof(cmd)); @@ -315,9 +204,11 @@ static int keyd_delete_key(uint64_t keyid, bool intrans) * TODO: Do we store multiple keys of the same id? Or only one and replace * it? */ -static int keyd_store_key(struct openpgp_publickey *publickey, bool intrans, +static int keyd_store_key(struct onak_dbctx *dbctx, + struct openpgp_publickey *publickey, bool intrans, bool update) { + int keyd_fd = (intptr_t) dbctx->priv; struct buffer_ctx keybuf; struct openpgp_packet_list *packets = NULL; struct openpgp_packet_list *list_end = NULL; @@ -329,9 +220,9 @@ static int keyd_store_key(struct openpgp_publickey *publickey, bool intrans, logthing(LOGTHING_ERROR, "Couldn't find key ID for key."); return 0; } - + if (update) { - keyd_delete_key(keyid, false); + keyd_delete_key(dbctx, keyid, false); } write(keyd_fd, &cmd, sizeof(cmd)); @@ -359,7 +250,7 @@ static int keyd_store_key(struct openpgp_publickey *publickey, bool intrans, keybuf.buffer = NULL; keybuf.size = keybuf.offset = 0; } - + return 0; } @@ -371,9 +262,11 @@ static int keyd_store_key(struct openpgp_publickey *publickey, bool intrans, * This function searches for the supplied text and returns the keys that * contain it. */ -static int keyd_fetch_key_text(const char *search, +static int keyd_fetch_key_text(struct onak_dbctx *dbctx, + const char *search, struct openpgp_publickey **publickey) { + int keyd_fd = (intptr_t) dbctx->priv; struct buffer_ctx keybuf; struct openpgp_packet_list *packets = NULL; uint32_t cmd = KEYD_CMD_GET_TEXT; @@ -411,15 +304,17 @@ static int keyd_fetch_key_text(const char *search, keybuf.size = 0; } } - + return (count > 0) ? 1 : 0; return 0; } -static int keyd_fetch_key_skshash(const struct skshash *hash, +static int keyd_fetch_key_skshash(struct onak_dbctx *dbctx, + const struct skshash *hash, struct openpgp_publickey **publickey) { + int keyd_fd = (intptr_t) dbctx->priv; struct buffer_ctx keybuf; struct openpgp_packet_list *packets = NULL; uint32_t cmd = KEYD_CMD_GET_SKSHASH; @@ -455,7 +350,7 @@ static int keyd_fetch_key_skshash(const struct skshash *hash, keybuf.size = 0; } } - + return (count > 0) ? 1 : 0; } @@ -467,8 +362,9 @@ static int keyd_fetch_key_skshash(const struct skshash *hash, * 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 keyd_getfullkeyid(uint64_t keyid) +static uint64_t keyd_getfullkeyid(struct onak_dbctx *dbctx, uint64_t keyid) { + int keyd_fd = (intptr_t) dbctx->priv; uint32_t cmd = KEYD_CMD_GETFULLKEYID; write(keyd_fd, &cmd, sizeof(cmd)); @@ -496,9 +392,11 @@ static uint64_t keyd_getfullkeyid(uint64_t keyid) * * Returns the number of keys we iterated over. */ -static int keyd_iterate_keys(void (*iterfunc)(void *ctx, +static int keyd_iterate_keys(struct onak_dbctx *dbctx, + void (*iterfunc)(void *ctx, struct openpgp_publickey *key), void *ctx) { + int keyd_fd = (intptr_t) dbctx->priv; struct buffer_ctx keybuf; struct openpgp_packet_list *packets = NULL; struct openpgp_publickey *key = NULL; @@ -546,7 +444,7 @@ static int keyd_iterate_keys(void (*iterfunc)(void *ctx, read(keyd_fd, &keybuf.size, sizeof(keybuf.size)); } } - + return numkeys; } @@ -555,21 +453,140 @@ static int keyd_iterate_keys(void (*iterfunc)(void *ctx, #define NEED_UPDATEKEYS 1 #include "keydb.c" -struct dbfuncs keydb_keyd_funcs = { - .initdb = keyd_initdb, - .cleanupdb = keyd_cleanupdb, - .starttrans = keyd_starttrans, - .endtrans = keyd_endtrans, - .fetch_key_id = keyd_fetch_key_id, - .fetch_key_fp = keyd_fetch_key_fp, - .fetch_key_text = keyd_fetch_key_text, - .fetch_key_skshash = keyd_fetch_key_skshash, - .store_key = keyd_store_key, - .update_keys = generic_update_keys, - .delete_key = keyd_delete_key, - .getkeysigs = generic_getkeysigs, - .cached_getkeysigs = generic_cached_getkeysigs, - .keyid2uid = generic_keyid2uid, - .getfullkeyid = keyd_getfullkeyid, - .iterate_keys = keyd_iterate_keys, -}; +/** + * cleanupdb - De-initialize the key database. + * + * This function should be called upon program exit to allow the DB to + * cleanup after itself. + */ +static void keyd_cleanupdb(struct onak_dbctx *dbctx) +{ + int keyd_fd = (intptr_t) dbctx->priv; + uint32_t cmd = KEYD_CMD_CLOSE; + + if (write(keyd_fd, &cmd, sizeof(cmd)) != sizeof(cmd)) { + logthing(LOGTHING_CRITICAL, + "Couldn't send close cmd: %s (%d)", + strerror(errno), + errno); + } + + if (read(keyd_fd, &cmd, sizeof(cmd)) != sizeof(cmd)) { + logthing(LOGTHING_CRITICAL, + "Couldn't read close cmd reply: %s (%d)", + strerror(errno), + errno); + } else if (cmd != KEYD_REPLY_OK) { + logthing(LOGTHING_CRITICAL, + "Got bad reply to KEYD_CMD_CLOSE: %d", cmd); + } + + if (shutdown(keyd_fd, SHUT_RDWR) < 0) { + logthing(LOGTHING_NOTICE, "Error shutting down socket: %d", + errno); + } + if (close(keyd_fd) < 0) { + logthing(LOGTHING_NOTICE, "Error closing down socket: %d", + errno); + } + keyd_fd = -1; + + free(dbctx); + + return; +} + +/** + * initdb - Initialize the key database. + * @readonly: If we'll only be reading the DB, not writing to it. + * + * This function should be called before any of the other functions in + * this file are called in order to allow the DB to be initialized ready + * for access. + */ +struct onak_dbctx *keydb_keyd_init(bool readonly) +{ + struct sockaddr_un sock; + uint32_t cmd = KEYD_CMD_UNKNOWN; + uint32_t reply = KEYD_REPLY_UNKNOWN_CMD; + ssize_t count; + int keyd_fd; + struct onak_dbctx *dbctx; + + dbctx = malloc(sizeof(*dbctx)); + if (dbctx == NULL) { + return NULL; + } + + keyd_fd = socket(PF_UNIX, SOCK_STREAM, 0); + if (keyd_fd < 0) { + logthing(LOGTHING_CRITICAL, + "Couldn't open socket: %s (%d)", + strerror(errno), + errno); + exit(EXIT_FAILURE); + } + + sock.sun_family = AF_UNIX; + snprintf(sock.sun_path, sizeof(sock.sun_path) - 1, "%s/%s", + config.db_dir, + KEYD_SOCKET); + if (connect(keyd_fd, (struct sockaddr *) &sock, sizeof(sock)) < 0) { + logthing(LOGTHING_CRITICAL, + "Couldn't connect to socket %s: %s (%d)", + sock.sun_path, + strerror(errno), + errno); + exit(EXIT_FAILURE); + } + + cmd = KEYD_CMD_VERSION; + if (write(keyd_fd, &cmd, sizeof(cmd)) != sizeof(cmd)) { + logthing(LOGTHING_CRITICAL, + "Couldn't write version cmd: %s (%d)", + strerror(errno), + errno); + } else { + count = read(keyd_fd, &reply, sizeof(reply)); + if (count == sizeof(reply) && reply == KEYD_REPLY_OK) { + count = read(keyd_fd, &reply, sizeof(reply)); + if (count != sizeof(reply) || reply != sizeof(reply)) { + logthing(LOGTHING_CRITICAL, + "Error! Unexpected keyd version " + "length: %d != %d", + reply, sizeof(reply)); + exit(EXIT_FAILURE); + } + + count = read(keyd_fd, &reply, sizeof(reply)); + logthing(LOGTHING_DEBUG, + "keyd protocol version %d", + reply); + if (reply != keyd_version) { + logthing(LOGTHING_CRITICAL, + "Error! keyd protocol version " + "mismatch. (us = %d, it = %d)", + keyd_version, reply); + } + } + } + + dbctx->priv = (void *) (intptr_t) keyd_fd; + dbctx->cleanupdb = keyd_cleanupdb; + dbctx->starttrans = keyd_starttrans; + dbctx->endtrans = keyd_endtrans; + dbctx->fetch_key_id = keyd_fetch_key_id; + dbctx->fetch_key_fp = keyd_fetch_key_fp; + dbctx->fetch_key_text = keyd_fetch_key_text; + dbctx->fetch_key_skshash = keyd_fetch_key_skshash; + dbctx->store_key = keyd_store_key; + dbctx->update_keys = generic_update_keys; + dbctx->delete_key = keyd_delete_key; + dbctx->getkeysigs = generic_getkeysigs; + dbctx->cached_getkeysigs = generic_cached_getkeysigs; + dbctx->keyid2uid = generic_keyid2uid; + dbctx->getfullkeyid = keyd_getfullkeyid; + dbctx->iterate_keys = keyd_iterate_keys; + + return dbctx; +} diff --git a/keydb_pg.c b/keydb_pg.c index 04c760d..ca7e35b 100644 --- a/keydb_pg.c +++ b/keydb_pg.c @@ -39,63 +39,29 @@ #include "onak-conf.h" #include "parsekey.h" -/** - * dbconn - our connection to the database. - */ -static PGconn *dbconn = NULL; +struct pg_fc_ctx { + PGconn *dbconn; + int fd; +}; /** * keydb_fetchchar - Fetches a char from a file. */ -static int keydb_fetchchar(void *fd, size_t count, void *c) +static int keydb_fetchchar(void *_ctx, size_t count, void *c) { - return (!lo_read(dbconn, *(int *) fd, (char *) c, count)); -} + struct pg_fc_ctx *ctx = (struct pg_fc_ctx *) _ctx; -/** - * keydb_putchar - Puts a char to a file. - */ -static int keydb_putchar(void *fd, size_t count, void *c) -{ - return !(lo_write(dbconn, *(int *) fd, (char *) c, count)); + return (!lo_read(ctx->dbconn, ctx->fd, (char *) c, count)); } /** - * initdb - Initialize the key database. - * - * This function should be called before any of the other functions in - * this file are called in order to allow the DB to be initialized ready - * for access. + * keydb_putchar - Puts a char to a file. */ -static void pg_initdb(bool readonly) +static int keydb_putchar(void *_ctx, size_t count, void *c) { - dbconn = PQsetdbLogin(config.pg_dbhost, // host - NULL, // port - NULL, // options - NULL, // tty - config.pg_dbname, // database - config.pg_dbuser, //login - config.pg_dbpass); // password + struct pg_fc_ctx *ctx = (struct pg_fc_ctx *) _ctx; - if (PQstatus(dbconn) == CONNECTION_BAD) { - logthing(LOGTHING_CRITICAL, "Connection to database failed."); - logthing(LOGTHING_CRITICAL, "%s", PQerrorMessage(dbconn)); - PQfinish(dbconn); - dbconn = NULL; - exit(1); - } -} - -/** - * cleanupdb - De-initialize the key database. - * - * This function should be called upon program exit to allow the DB to - * cleanup after itself. - */ -static void pg_cleanupdb(void) -{ - PQfinish(dbconn); - dbconn = NULL; + return !(lo_write(ctx->dbconn, ctx->fd, (char *) c, count)); } /** @@ -105,8 +71,9 @@ static void pg_cleanupdb(void) * operations on the database to help speed it all up, or if we want * something to only succeed if all relevant operations are successful. */ -static bool pg_starttrans(void) +static bool pg_starttrans(struct onak_dbctx *dbctx) { + PGconn *dbconn = (PGconn *) dbctx->priv; PGresult *result = NULL; result = PQexec(dbconn, "BEGIN"); @@ -120,8 +87,9 @@ static bool pg_starttrans(void) * * Ends a transaction. */ -static void pg_endtrans(void) +static void pg_endtrans(struct onak_dbctx *dbctx) { + PGconn *dbconn = (PGconn *) dbctx->priv; PGresult *result = NULL; result = PQexec(dbconn, "COMMIT"); @@ -142,18 +110,20 @@ static void pg_endtrans(void) * in and then parse_keys() to parse the packets into a publickey * structure. */ -static int pg_fetch_key_id(uint64_t keyid, +static int pg_fetch_key_id(struct onak_dbctx *dbctx, + uint64_t keyid, struct openpgp_publickey **publickey, bool intrans) { struct openpgp_packet_list *packets = NULL; + PGconn *dbconn = (PGconn *) dbctx->priv; PGresult *result = NULL; char *oids = NULL; char statement[1024]; - int fd = -1; int i = 0; int numkeys = 0; Oid key_oid; + struct pg_fc_ctx fcctx; if (!intrans) { result = PQexec(dbconn, "BEGIN"); @@ -179,15 +149,16 @@ static int pg_fetch_key_id(uint64_t keyid, oids = PQgetvalue(result, i, 0); key_oid = (Oid) atoi(oids); - fd = lo_open(dbconn, key_oid, INV_READ); - if (fd < 0) { + fcctx.fd = lo_open(dbconn, key_oid, INV_READ); + if (fcctx.fd < 0) { logthing(LOGTHING_ERROR, "Can't open large object."); } else { - read_openpgp_stream(keydb_fetchchar, &fd, + fcctx.dbconn = dbconn; + read_openpgp_stream(keydb_fetchchar, &fcctx, &packets, 0); parse_keys(packets, publickey); - lo_close(dbconn, fd); + lo_close(dbconn, fcctx.fd); free_packet_list(packets); packets = NULL; } @@ -213,18 +184,20 @@ static int pg_fetch_key_id(uint64_t keyid, * This function searches for the supplied text and returns the keys that * contain it. */ -static int pg_fetch_key_text(const char *search, +static int pg_fetch_key_text(struct onak_dbctx *dbctx, + const char *search, struct openpgp_publickey **publickey) { struct openpgp_packet_list *packets = NULL; + PGconn *dbconn = (PGconn *) dbctx->priv; PGresult *result = NULL; char *oids = NULL; char statement[1024]; - int fd = -1; int i = 0; int numkeys = 0; Oid key_oid; char *newsearch = NULL; + struct pg_fc_ctx fcctx; result = PQexec(dbconn, "BEGIN"); PQclear(result); @@ -247,16 +220,17 @@ static int pg_fetch_key_text(const char *search, oids = PQgetvalue(result, i, 0); key_oid = (Oid) atoi(oids); - fd = lo_open(dbconn, key_oid, INV_READ); - if (fd < 0) { + fcctx.fd = lo_open(dbconn, key_oid, INV_READ); + if (fcctx.fd < 0) { logthing(LOGTHING_ERROR, "Can't open large object."); } else { - read_openpgp_stream(keydb_fetchchar, &fd, + fcctx.dbconn = dbconn; + read_openpgp_stream(keydb_fetchchar, &fcctx, &packets, 0); parse_keys(packets, publickey); - lo_close(dbconn, fd); + lo_close(dbconn, fcctx.fd); free_packet_list(packets); packets = NULL; } @@ -280,8 +254,9 @@ static int pg_fetch_key_text(const char *search, * This function deletes a public key from whatever storage mechanism we * are using. Returns 0 if the key existed. */ -static int pg_delete_key(uint64_t keyid, bool intrans) +static int pg_delete_key(struct onak_dbctx *dbctx, uint64_t keyid, bool intrans) { + PGconn *dbconn = (PGconn *) dbctx->priv; PGresult *result = NULL; char *oids = NULL; char statement[1024]; @@ -355,22 +330,24 @@ static int pg_delete_key(uint64_t keyid, bool intrans) * the file. If update is true then we delete the old key first, otherwise * we trust that it doesn't exist. */ -static int pg_store_key(struct openpgp_publickey *publickey, bool intrans, +static int pg_store_key(struct onak_dbctx *dbctx, + struct openpgp_publickey *publickey, bool intrans, bool update) { struct openpgp_packet_list *packets = NULL; struct openpgp_packet_list *list_end = NULL; struct openpgp_publickey *next = NULL; struct openpgp_signedpacket_list *curuid = NULL; + PGconn *dbconn = (PGconn *) dbctx->priv; PGresult *result = NULL; char statement[1024]; Oid key_oid; - int fd; char **uids = NULL; char *primary = NULL; char *safeuid = NULL; int i; uint64_t keyid; + struct pg_fc_ctx fcctx; if (!intrans) { result = PQexec(dbconn, "BEGIN"); @@ -391,7 +368,7 @@ static int pg_store_key(struct openpgp_publickey *publickey, bool intrans, * it definitely needs updated. */ if (update) { - pg_delete_key(keyid, true); + pg_delete_key(dbctx, keyid, true); } next = publickey->next; @@ -403,9 +380,10 @@ static int pg_store_key(struct openpgp_publickey *publickey, bool intrans, if (key_oid == 0) { logthing(LOGTHING_ERROR, "Can't create key OID"); } else { - fd = lo_open(dbconn, key_oid, INV_WRITE); - write_openpgp_stream(keydb_putchar, &fd, packets); - lo_close(dbconn, fd); + fcctx.fd = lo_open(dbconn, key_oid, INV_WRITE); + fcctx.dbconn = dbconn; + write_openpgp_stream(keydb_putchar, &fcctx, packets); + lo_close(dbconn, fcctx.fd); } free_packet_list(packets); packets = NULL; @@ -489,8 +467,9 @@ static int pg_store_key(struct openpgp_publickey *publickey, bool intrans, * keyid2uid - Takes a keyid and returns the primary UID for it. * @keyid: The keyid to lookup. */ -static char *pg_keyid2uid(uint64_t keyid) +static char *pg_keyid2uid(struct onak_dbctx *dbctx, uint64_t keyid) { + PGconn *dbconn = (PGconn *) dbctx->priv; PGresult *result = NULL; char statement[1024]; char *uid = NULL; @@ -531,9 +510,11 @@ static char *pg_keyid2uid(uint64_t keyid) * This function gets the list of signatures on a key. Used for key * indexing and doing stats bits. */ -static struct ll *pg_getkeysigs(uint64_t keyid, bool *revoked) +static struct ll *pg_getkeysigs(struct onak_dbctx *dbctx, + uint64_t keyid, bool *revoked) { struct ll *sigs = NULL; + PGconn *dbconn = (PGconn *) dbctx->priv; PGresult *result = NULL; uint64_t signer; char statement[1024]; @@ -604,17 +585,19 @@ static struct ll *pg_getkeysigs(uint64_t keyid, bool *revoked) * * Returns the number of keys we iterated over. */ -static int pg_iterate_keys(void (*iterfunc)(void *ctx, +static int pg_iterate_keys(struct onak_dbctx *dbctx, + void (*iterfunc)(void *ctx, struct openpgp_publickey *key), void *ctx) { struct openpgp_packet_list *packets = NULL; struct openpgp_publickey *key = NULL; + PGconn *dbconn = (PGconn *) dbctx->priv; PGresult *result = NULL; char *oids = NULL; - int fd = -1; int i = 0; int numkeys = 0; Oid key_oid; + struct pg_fc_ctx fcctx; result = PQexec(dbconn, "SELECT keydata FROM onak_keys;"); @@ -624,15 +607,16 @@ static int pg_iterate_keys(void (*iterfunc)(void *ctx, oids = PQgetvalue(result, i, 0); key_oid = (Oid) atoi(oids); - fd = lo_open(dbconn, key_oid, INV_READ); - if (fd < 0) { + fcctx.fd = lo_open(dbconn, key_oid, INV_READ); + if (fcctx.fd < 0) { logthing(LOGTHING_ERROR, "Can't open large object."); } else { - read_openpgp_stream(keydb_fetchchar, &fd, + fcctx.dbconn = dbconn; + read_openpgp_stream(keydb_fetchchar, &fcctx, &packets, 0); parse_keys(packets, &key); - lo_close(dbconn, fd); + lo_close(dbconn, fcctx.fd); iterfunc(ctx, key); @@ -659,20 +643,71 @@ static int pg_iterate_keys(void (*iterfunc)(void *ctx, #define NEED_GET_FP 1 #include "keydb.c" -struct dbfuncs keydb_pg_funcs = { - .initdb = pg_initdb, - .cleanupdb = pg_cleanupdb, - .starttrans = pg_starttrans, - .endtrans = pg_endtrans, - .fetch_key_id = pg_fetch_key_id, - .fetch_key_fp = generic_fetch_key_fp, - .fetch_key_text = pg_fetch_key_text, - .store_key = pg_store_key, - .update_keys = generic_update_keys, - .delete_key = pg_delete_key, - .getkeysigs = pg_getkeysigs, - .cached_getkeysigs = generic_cached_getkeysigs, - .keyid2uid = pg_keyid2uid, - .getfullkeyid = generic_getfullkeyid, - .iterate_keys = pg_iterate_keys, -}; +/** + * cleanupdb - De-initialize the key database. + * + * This function should be called upon program exit to allow the DB to + * cleanup after itself. + */ +static void pg_cleanupdb(struct onak_dbctx *dbctx) +{ + PGconn *dbconn = (PGconn *) dbctx->priv; + + PQfinish(dbconn); + dbconn = NULL; + + free(dbctx); +} + +/** + * initdb - Initialize the key database. + * + * This function should be called before any of the other functions in + * this file are called in order to allow the DB to be initialized ready + * for access. + */ +struct onak_dbctx *keydb_pg_init(bool readonly) +{ + struct onak_dbctx *dbctx; + PGconn *dbconn; + + dbctx = malloc(sizeof(struct onak_dbctx)); + if (dbctx == NULL) { + return NULL; + } + + dbconn = PQsetdbLogin(config.pg_dbhost, // host + NULL, // port + NULL, // options + NULL, // tty + config.pg_dbname, // database + config.pg_dbuser, //login + config.pg_dbpass); // password + + if (PQstatus(dbconn) == CONNECTION_BAD) { + logthing(LOGTHING_CRITICAL, "Connection to database failed."); + logthing(LOGTHING_CRITICAL, "%s", PQerrorMessage(dbconn)); + PQfinish(dbconn); + dbconn = NULL; + exit(1); + } + + dbctx->priv = dbconn; + + dbctx->cleanupdb = pg_cleanupdb; + dbctx->starttrans = pg_starttrans; + dbctx->endtrans = pg_endtrans; + dbctx->fetch_key_id = pg_fetch_key_id; + dbctx->fetch_key_fp = generic_fetch_key_fp; + dbctx->fetch_key_text = pg_fetch_key_text; + dbctx->store_key = pg_store_key; + dbctx->update_keys = generic_update_keys; + dbctx->delete_key = pg_delete_key; + dbctx->getkeysigs = pg_getkeysigs; + dbctx->cached_getkeysigs = generic_cached_getkeysigs; + dbctx->keyid2uid = pg_keyid2uid; + dbctx->getfullkeyid = generic_getfullkeyid; + dbctx->iterate_keys = pg_iterate_keys; + + return dbctx; +} diff --git a/keydctl.c b/keydctl.c index 4ffecae..47492c5 100644 --- a/keydctl.c +++ b/keydctl.c @@ -32,7 +32,7 @@ #include "version.h" /* HACK: We need to stop onak-conf.o requiring this. */ -void *DBFUNCS = NULL; +void *DBINIT = NULL; static int keyd_fd = -1; static int verbose = 0; diff --git a/keyindex.c b/keyindex.c index f3c36aa..4ca6a41 100644 --- a/keyindex.c +++ b/keyindex.c @@ -138,7 +138,8 @@ unsigned int keylength(struct openpgp_packet *keydata) return length; } -int list_sigs(struct openpgp_packet_list *sigs, bool html) +int list_sigs(struct onak_dbctx *dbctx, + struct openpgp_packet_list *sigs, bool html) { char *uid = NULL; uint64_t sigid = 0; @@ -146,7 +147,7 @@ int list_sigs(struct openpgp_packet_list *sigs, bool html) while (sigs != NULL) { sigid = sig_keyid(sigs->packet); - uid = config.dbbackend->keyid2uid(sigid); + uid = dbctx->keyid2uid(dbctx, sigid); if (sigs->packet->data[0] == 4 && sigs->packet->data[1] == 0x30) { /* It's a Type 4 sig revocation */ @@ -188,7 +189,8 @@ int list_sigs(struct openpgp_packet_list *sigs, bool html) return 0; } -int list_uids(uint64_t keyid, struct openpgp_signedpacket_list *uids, +int list_uids(struct onak_dbctx *dbctx, + uint64_t keyid, struct openpgp_signedpacket_list *uids, bool verbose, bool html) { char buf[1024]; @@ -215,7 +217,7 @@ int list_uids(uint64_t keyid, struct openpgp_signedpacket_list *uids, } } if (verbose) { - list_sigs(uids->sigs, html); + list_sigs(dbctx, uids->sigs, html); } uids = uids->next; } @@ -223,7 +225,8 @@ int list_uids(uint64_t keyid, struct openpgp_signedpacket_list *uids, return 0; } -int list_subkeys(struct openpgp_signedpacket_list *subkeys, bool verbose, +int list_subkeys(struct onak_dbctx *dbctx, + struct openpgp_signedpacket_list *subkeys, bool verbose, bool html) { struct tm *created = NULL; @@ -270,7 +273,7 @@ int list_subkeys(struct openpgp_signedpacket_list *subkeys, bool verbose, } if (verbose) { - list_sigs(subkeys->sigs, html); + list_sigs(dbctx, subkeys->sigs, html); } subkeys = subkeys->next; } @@ -337,7 +340,8 @@ void display_skshash(struct openpgp_publickey *key, bool html) * This function takes a list of OpenPGP public keys and displays an index * of them. Useful for debugging or the keyserver Index function. */ -int key_index(struct openpgp_publickey *keys, bool verbose, bool fingerprint, +int key_index(struct onak_dbctx *dbctx, + struct openpgp_publickey *keys, bool verbose, bool fingerprint, bool skshash, bool html) { struct openpgp_signedpacket_list *curuid = NULL; @@ -420,7 +424,7 @@ int key_index(struct openpgp_publickey *keys, bool verbose, bool fingerprint, display_fingerprint(keys); } if (verbose) { - list_sigs(curuid->sigs, html); + list_sigs(dbctx, curuid->sigs, html); } curuid = curuid->next; } else { @@ -431,9 +435,9 @@ int key_index(struct openpgp_publickey *keys, bool verbose, bool fingerprint, } } - list_uids(keyid, curuid, verbose, html); + list_uids(dbctx, keyid, curuid, verbose, html); if (verbose) { - list_subkeys(keys->subkeys, verbose, html); + list_subkeys(dbctx, keys->subkeys, verbose, html); } keys = keys->next; diff --git a/keyindex.h b/keyindex.h index c9a5843..8a4e529 100644 --- a/keyindex.h +++ b/keyindex.h @@ -22,6 +22,7 @@ #include +#include "keydb.h" #include "keystructs.h" /** @@ -35,7 +36,8 @@ * This function takes a list of OpenPGP public keys and displays an index * of them. Useful for debugging or the keyserver Index function. */ -int key_index(struct openpgp_publickey *keys, bool verbose, +int key_index(struct onak_dbctx *dbctx, + struct openpgp_publickey *keys, bool verbose, bool fingerprint, bool skshash, bool html); /** diff --git a/lookup.c b/lookup.c index 13ffbcc..533433a 100644 --- a/lookup.c +++ b/lookup.c @@ -46,7 +46,8 @@ #define OP_PHOTO 4 #define OP_HGET 5 -void find_keys(char *search, uint64_t keyid, uint8_t *fp, size_t fpsize, +void find_keys(struct onak_dbctx *dbctx, + char *search, uint64_t keyid, uint8_t *fp, size_t fpsize, bool ishex, bool isfp, bool fingerprint, bool skshash, bool exact, bool verbose, bool mrhkp) { @@ -54,21 +55,21 @@ void find_keys(char *search, uint64_t keyid, uint8_t *fp, size_t fpsize, int count = 0; if (ishex) { - count = config.dbbackend->fetch_key_id(keyid, &publickey, + count = dbctx->fetch_key_id(dbctx, keyid, &publickey, false); } else if (isfp) { - count = config.dbbackend->fetch_key_fp(fp, fpsize, &publickey, + count = dbctx->fetch_key_fp(dbctx, fp, fpsize, &publickey, false); } else { - count = config.dbbackend->fetch_key_text(search, &publickey); + count = dbctx->fetch_key_text(dbctx, search, &publickey); } if (publickey != NULL) { if (mrhkp) { printf("info:1:%d\n", count); mrkey_index(publickey); } else { - key_index(publickey, verbose, fingerprint, skshash, - true); + key_index(dbctx, publickey, verbose, fingerprint, + skshash, true); } free_publickey(publickey); } else if (count == 0) { @@ -124,6 +125,7 @@ int main(int argc, char *argv[]) struct openpgp_packet_list *list_end = NULL; int result; struct skshash hash; + struct onak_dbctx *dbctx; params = getcgivars(argc, argv); for (i = 0; params != NULL && params[i] != NULL; i += 2) { @@ -210,22 +212,22 @@ int main(int argc, char *argv[]) readconfig(NULL); initlogthing("lookup", config.logfile); catchsignals(); - config.dbbackend->initdb(false); + dbctx = config.dbinit(false); switch (op) { case OP_GET: case OP_HGET: if (op == OP_HGET) { parse_skshash(search, &hash); - result = config.dbbackend->fetch_key_skshash( + result = dbctx->fetch_key_skshash(dbctx, &hash, &publickey); } else if (ishex) { - result = config.dbbackend->fetch_key_id(keyid, + result = dbctx->fetch_key_id(dbctx, keyid, &publickey, false); } else if (isfp) { - result = config.dbbackend->fetch_key_fp(fp, + result = dbctx->fetch_key_fp(dbctx, fp, MAX_FINGERPRINT_LEN, &publickey, false); } else { - result = config.dbbackend->fetch_key_text( + result = dbctx->fetch_key_text(dbctx, search, &publickey); } @@ -251,22 +253,22 @@ int main(int argc, char *argv[]) } break; case OP_INDEX: - find_keys(search, keyid, fp, MAX_FINGERPRINT_LEN, + find_keys(dbctx, search, keyid, fp, MAX_FINGERPRINT_LEN, ishex, isfp, fingerprint, skshash, exact, false, mrhkp); break; case OP_VINDEX: - find_keys(search, keyid, fp, MAX_FINGERPRINT_LEN, + find_keys(dbctx, search, keyid, fp, MAX_FINGERPRINT_LEN, ishex, isfp, fingerprint, skshash, exact, true, mrhkp); break; case OP_PHOTO: if (isfp) { - config.dbbackend->fetch_key_fp(fp, + dbctx->fetch_key_fp(dbctx, fp, MAX_FINGERPRINT_LEN, &publickey, false); } else { - config.dbbackend->fetch_key_id(keyid, + dbctx->fetch_key_id(dbctx, keyid, &publickey, false); } if (publickey != NULL) { @@ -287,7 +289,7 @@ int main(int argc, char *argv[]) default: puts("Unknown operation!"); } - config.dbbackend->cleanupdb(); + dbctx->cleanupdb(dbctx); cleanuplogthing(); cleanupconfig(); } diff --git a/maxpath.c b/maxpath.c index 25264ce..fbd5a17 100644 --- a/maxpath.c +++ b/maxpath.c @@ -30,7 +30,7 @@ #include "onak-conf.h" #include "stats.h" -void findmaxpath(unsigned long max) +void findmaxpath(struct onak_dbctx *dbctx, unsigned long max) { struct stats_key *from, *to, *tmp; struct ll *curkey; @@ -43,7 +43,7 @@ void findmaxpath(unsigned long max) * My (noodles@earth.li, RSA) key is in the strongly connected set of * keys, so we use it as a suitable starting seed. */ - config.dbbackend->cached_getkeysigs(0x94FA372B2DA8B985); + dbctx->cached_getkeysigs(dbctx, 0x94FA372B2DA8B985); /* * Loop through the hash examining each key present and finding the @@ -54,11 +54,11 @@ void findmaxpath(unsigned long max) for (loop = 0; (loop < HASHSIZE) && (distance < max); loop++) { curkey = gethashtableentry(loop); while (curkey != NULL && distance < max) { - config.dbbackend->cached_getkeysigs( + dbctx->cached_getkeysigs(dbctx, ((struct stats_key *) curkey->object)->keyid); initcolour(false); - tmp = furthestkey((struct stats_key *) + tmp = furthestkey(dbctx, (struct stats_key *) curkey->object); if (tmp->colour > distance) { from = (struct stats_key *)curkey->object; @@ -79,13 +79,14 @@ void findmaxpath(unsigned long max) from->keyid, to->keyid, distance); - dofindpath(to->keyid, from->keyid, false, 1); + dofindpath(dbctx, to->keyid, from->keyid, false, 1); } int main(int argc, char *argv[]) { int optchar; char *configfile = NULL; + struct onak_dbctx *dbctx; while ((optchar = getopt(argc, argv, "c:")) != -1 ) { switch (optchar) { @@ -97,13 +98,17 @@ int main(int argc, char *argv[]) readconfig(configfile); initlogthing("maxpath", config.logfile); - config.dbbackend->initdb(true); - inithash(); - findmaxpath(30); - printf("--------\n"); - findmaxpath(30); - destroyhash(); - config.dbbackend->cleanupdb(); + dbctx = config.dbinit(true); + if (dbctx != NULL) { + inithash(); + findmaxpath(dbctx, 30); + printf("--------\n"); + findmaxpath(dbctx, 30); + destroyhash(); + dbctx->cleanupdb(dbctx); + } else { + fprintf(stderr, "Couldn't initialize key database.\n"); + } cleanuplogthing(); cleanupconfig(); diff --git a/onak-conf.c b/onak-conf.c index a29a58b..e3085e1 100644 --- a/onak-conf.c +++ b/onak-conf.c @@ -28,7 +28,7 @@ #include "log.h" #include "onak-conf.h" -extern struct dbfuncs DBFUNCS; +extern struct onak_dbctx *DBINIT(bool readonly); /* * config - Runtime configuration for onak. @@ -65,7 +65,7 @@ struct onak_config config = { NULL, /* db_backend */ NULL, /* backends_dir */ - &DBFUNCS, /* Default dbfuncs struct */ + DBINIT, /* Default db initialisation function */ true, /* Check packet sig hashes */ }; diff --git a/onak-conf.h b/onak-conf.h index 2a9e335..34dcff2 100644 --- a/onak-conf.h +++ b/onak-conf.h @@ -76,8 +76,8 @@ struct onak_config { /** Directory where backend .so files can be found */ char *backends_dir; - /** Pointer to the function table for our loaded DB backend */ - struct dbfuncs *dbbackend; + /** Pointer to the initialisation function for our loaded DB backend */ + struct onak_dbctx *(*dbinit)(bool); /** Should we verify signature hashes match? */ bool check_sighash; diff --git a/onak.c b/onak.c index f67c969..dd39bb3 100644 --- a/onak.c +++ b/onak.c @@ -44,7 +44,8 @@ #include "photoid.h" #include "version.h" -void find_keys(char *search, uint64_t keyid, uint8_t *fp, bool ishex, +void find_keys(struct onak_dbctx *dbctx, + char *search, uint64_t keyid, uint8_t *fp, bool ishex, bool isfp, bool fingerprint, bool skshash, bool exact, bool verbose) { @@ -52,16 +53,17 @@ void find_keys(char *search, uint64_t keyid, uint8_t *fp, bool ishex, int count = 0; if (ishex) { - count = config.dbbackend->fetch_key_id(keyid, &publickey, + count = dbctx->fetch_key_id(dbctx, keyid, &publickey, false); } else if (isfp) { - count = config.dbbackend->fetch_key_fp(fp, MAX_FINGERPRINT_LEN, + count = dbctx->fetch_key_fp(dbctx, fp, MAX_FINGERPRINT_LEN, &publickey, false); } else { - count = config.dbbackend->fetch_key_text(search, &publickey); + count = dbctx->fetch_key_text(dbctx, search, &publickey); } if (publickey != NULL) { - key_index(publickey, verbose, fingerprint, skshash, false); + key_index(dbctx, publickey, verbose, fingerprint, skshash, + false); free_publickey(publickey); } else if (count == 0) { puts("Key not found."); @@ -172,6 +174,7 @@ int main(int argc, char *argv[]) int optchar; struct dump_ctx dumpstate; struct skshash hash; + struct onak_dbctx *dbctx; while ((optchar = getopt(argc, argv, "bc:fsuv")) != -1 ) { switch (optchar) { @@ -204,17 +207,17 @@ int main(int argc, char *argv[]) if ((argc - optind) < 1) { usage(); } else if (!strcmp("dump", argv[optind])) { - config.dbbackend->initdb(true); + dbctx = config.dbinit(true); dumpstate.count = dumpstate.filenum = 0; dumpstate.maxcount = 100000; dumpstate.fd = -1; dumpstate.filebase = "keydump.%d.pgp"; - config.dbbackend->iterate_keys(dump_func, &dumpstate); + dbctx->iterate_keys(dbctx, dump_func, &dumpstate); if (dumpstate.fd != -1) { close(dumpstate.fd); dumpstate.fd = -1; } - config.dbbackend->cleanupdb(); + dbctx->cleanupdb(dbctx); } else if (!strcmp("add", argv[optind])) { if (binary) { result = read_openpgp_stream(stdin_getchar, NULL, @@ -235,9 +238,9 @@ int main(int argc, char *argv[]) logthing(LOGTHING_INFO, "%d keys cleaned.", result); - config.dbbackend->initdb(false); + dbctx = config.dbinit(false); logthing(LOGTHING_NOTICE, "Got %d new keys.", - config.dbbackend->update_keys(&keys, + dbctx->update_keys(dbctx, &keys, false)); if (keys != NULL && update) { flatten_publickey(keys, @@ -255,7 +258,7 @@ int main(int argc, char *argv[]) free_packet_list(packets); packets = NULL; } - config.dbbackend->cleanupdb(); + dbctx->cleanupdb(dbctx); } else { rc = 1; logthing(LOGTHING_NOTICE, "No keys read."); @@ -332,20 +335,20 @@ int main(int argc, char *argv[]) ishex = true; } } - config.dbbackend->initdb(false); + dbctx = config.dbinit(false); if (!strcmp("index", argv[optind])) { - find_keys(search, keyid, fp, ishex, isfp, + find_keys(dbctx, search, keyid, fp, ishex, isfp, fingerprint, skshash, false, false); } else if (!strcmp("vindex", argv[optind])) { - find_keys(search, keyid, fp, ishex, isfp, + find_keys(dbctx, search, keyid, fp, ishex, isfp, fingerprint, skshash, false, true); } else if (!strcmp("getphoto", argv[optind])) { if (!ishex) { puts("Can't get a key on uid text." " You must supply a keyid."); - } else if (config.dbbackend->fetch_key_id(keyid, &keys, + } else if (dbctx->fetch_key_id(dbctx, keyid, &keys, false)) { unsigned char *photo = NULL; size_t length = 0; @@ -363,8 +366,8 @@ int main(int argc, char *argv[]) puts("Key not found"); } } else if (!strcmp("delete", argv[optind])) { - config.dbbackend->delete_key( - config.dbbackend->getfullkeyid(keyid), + dbctx->delete_key(dbctx, + dbctx->getfullkeyid(dbctx, keyid), false); } else if (!strcmp("get", argv[optind])) { if (!(ishex || isfp)) { @@ -372,11 +375,11 @@ int main(int argc, char *argv[]) " You must supply a keyid / " "fingerprint."); } else if ((isfp && - config.dbbackend->fetch_key_fp(fp, + dbctx->fetch_key_fp(dbctx, fp, MAX_FINGERPRINT_LEN, &keys, false)) || (ishex && - config.dbbackend->fetch_key_id(keyid, + dbctx->fetch_key_id(dbctx, keyid, &keys, false))) { logthing(LOGTHING_INFO, "Got key."); flatten_publickey(keys, @@ -400,7 +403,7 @@ int main(int argc, char *argv[]) } else if (!strcmp("hget", argv[optind])) { if (!parse_skshash(search, &hash)) { puts("Couldn't parse sks hash."); - } else if (config.dbbackend->fetch_key_skshash(&hash, + } else if (dbctx->fetch_key_skshash(dbctx, &hash, &keys)) { logthing(LOGTHING_INFO, "Got key."); flatten_publickey(keys, @@ -422,7 +425,7 @@ int main(int argc, char *argv[]) puts("Key not found"); } } - config.dbbackend->cleanupdb(); + dbctx->cleanupdb(dbctx); } else { usage(); } diff --git a/sixdegrees.c b/sixdegrees.c index 738f626..a842230 100644 --- a/sixdegrees.c +++ b/sixdegrees.c @@ -30,7 +30,8 @@ #include "onak-conf.h" #include "stats.h" -unsigned long countdegree(struct stats_key *have, bool sigs, int maxdegree) +unsigned long countdegree(struct onak_dbctx *dbctx, + struct stats_key *have, bool sigs, int maxdegree) { unsigned long count = 0, curdegree = 0; struct ll *curll, *nextll, *sigll, *tmp; @@ -43,7 +44,7 @@ unsigned long countdegree(struct stats_key *have, bool sigs, int maxdegree) while (curll != NULL && curdegree <= maxdegree) { if (sigs) { - sigll = config.dbbackend->cached_getkeysigs( + sigll = dbctx->cached_getkeysigs(dbctx, ((struct stats_key *) curll->object)->keyid); } else { @@ -89,21 +90,21 @@ unsigned long countdegree(struct stats_key *have, bool sigs, int maxdegree) return count; } -void sixdegrees(uint64_t keyid) +void sixdegrees(struct onak_dbctx *dbctx, uint64_t keyid) { struct stats_key *keyinfo; int loop; long degree; char *uid; - config.dbbackend->cached_getkeysigs(keyid); + dbctx->cached_getkeysigs(dbctx, keyid); if ((keyinfo = findinhash(keyid)) == NULL) { printf("Couldn't find key 0x%016" PRIX64 ".\n", keyid); return; } - uid = config.dbbackend->keyid2uid(keyinfo->keyid); + uid = dbctx->keyid2uid(dbctx, keyinfo->keyid); printf("Six degrees for 0x%016" PRIX64 " (%s):\n", keyinfo->keyid, uid); free(uid); @@ -118,16 +119,16 @@ void sixdegrees(uint64_t keyid) * if it's signed by the key we're looking at. */ initcolour(false); - degree = countdegree(keyinfo, true, 7); + degree = countdegree(dbctx, keyinfo, true, 7); puts("\t\tSigned by\t\tSigns"); for (loop = 1; loop < 7; loop++) { initcolour(false); - degree = countdegree(keyinfo, true, loop); + degree = countdegree(dbctx, keyinfo, true, loop); printf("Degree %d:\t%8ld", loop, degree); initcolour(false); - degree = countdegree(keyinfo, false, loop); + degree = countdegree(dbctx, keyinfo, false, loop); printf("\t\t%8ld\n", degree); } } @@ -137,6 +138,7 @@ int main(int argc, char *argv[]) int optchar; char *configfile = NULL; uint64_t keyid = 0x2DA8B985; + struct onak_dbctx *dbctx; while ((optchar = getopt(argc, argv, "c:")) != -1 ) { switch (optchar) { @@ -152,11 +154,15 @@ int main(int argc, char *argv[]) readconfig(configfile); initlogthing("sixdegrees", config.logfile); - config.dbbackend->initdb(true); - inithash(); - sixdegrees(config.dbbackend->getfullkeyid(keyid)); - destroyhash(); - config.dbbackend->cleanupdb(); + dbctx = config.dbinit(true); + if (dbctx != NULL) { + inithash(); + sixdegrees(dbctx, dbctx->getfullkeyid(dbctx, keyid)); + destroyhash(); + dbctx->cleanupdb(dbctx); + } else { + fprintf(stderr, "Couldn't initialize key database.\n"); + } cleanuplogthing(); cleanupconfig(); diff --git a/stats.c b/stats.c index bcc4f91..a656508 100644 --- a/stats.c +++ b/stats.c @@ -66,7 +66,8 @@ void initcolour(bool parent) * key we have. It returns as soon as a path is found or when we run out * of keys; whichever comes sooner. */ -unsigned long findpath(struct stats_key *have, struct stats_key *want) +unsigned long findpath(struct onak_dbctx *dbctx, + struct stats_key *have, struct stats_key *want) { struct ll *keys = NULL; struct ll *oldkeys = NULL; @@ -80,7 +81,7 @@ unsigned long findpath(struct stats_key *have, struct stats_key *want) oldkeys = keys; while ((!cleanup()) && keys != NULL && have->colour == 0) { - sigs = config.dbbackend->cached_getkeysigs(((struct stats_key *) + sigs = dbctx->cached_getkeysigs(dbctx, ((struct stats_key *) keys->object)->keyid); while ((!cleanup()) && sigs != NULL && have->colour == 0) { /* @@ -132,7 +133,8 @@ unsigned long findpath(struct stats_key *have, struct stats_key *want) * key we have. It returns as soon as a path is found or when we run out * of keys; whichever comes sooner. */ -void dofindpath(uint64_t have, uint64_t want, bool html, int count) +void dofindpath(struct onak_dbctx *dbctx, + uint64_t have, uint64_t want, bool html, int count) { struct stats_key *keyinfoa, *keyinfob, *curkey; uint64_t fullhave, fullwant; @@ -140,14 +142,14 @@ void dofindpath(uint64_t have, uint64_t want, bool html, int count) int pathnum; char *uid; - fullhave = config.dbbackend->getfullkeyid(have); - fullwant = config.dbbackend->getfullkeyid(want); + fullhave = dbctx->getfullkeyid(dbctx, have); + fullwant = dbctx->getfullkeyid(dbctx, want); /* * Make sure the keys we have and want are in the cache. */ - (void) config.dbbackend->cached_getkeysigs(fullhave); - (void) config.dbbackend->cached_getkeysigs(fullwant); + (void) dbctx->cached_getkeysigs(dbctx, fullhave); + (void) dbctx->cached_getkeysigs(dbctx, fullwant); if ((keyinfoa = findinhash(fullhave)) == NULL) { printf("Couldn't find key 0x%016" PRIX64 ".\n", have); @@ -165,7 +167,7 @@ void dofindpath(uint64_t have, uint64_t want, bool html, int count) * Fill the tree info up. */ initcolour(true); - rec = findpath(keyinfoa, keyinfob); + rec = findpath(dbctx, keyinfoa, keyinfob); keyinfob->parent = 0; printf("%s%d nodes examined. %ld elements in the hash%s\n", @@ -193,7 +195,7 @@ void dofindpath(uint64_t have, uint64_t want, bool html, int count) html ? "
" : ""); curkey = keyinfoa; while (curkey != NULL && curkey->keyid != 0) { - uid = config.dbbackend->keyid2uid( + uid = dbctx->keyid2uid(dbctx, curkey->keyid); if (html && uid == NULL) { printf("cached_getkeysigs(((struct stats_key *) + sigs = dbctx->cached_getkeysigs(dbctx, ((struct stats_key *) curll->object)->keyid); while (sigs != NULL) { if (((struct stats_key *) sigs->object)->colour == 0) { diff --git a/stats.h b/stats.h index 08e2abe..991bb1c 100644 --- a/stats.h +++ b/stats.h @@ -33,6 +33,7 @@ key_getsigns - get the keys a key signs. */ #include #include +#include "keydb.h" #include "ll.h" /** @@ -75,7 +76,8 @@ void initcolour(bool parent); * key we have. It returns as soon as a path is found or when we run out * of keys; whichever comes sooner. */ -unsigned long findpath(struct stats_key *have, struct stats_key *want); +unsigned long findpath(struct onak_dbctx *dbctx, + struct stats_key *have, struct stats_key *want); /** * dofindpath - Given 2 keys displays a path between them. @@ -88,8 +90,9 @@ unsigned long findpath(struct stats_key *have, struct stats_key *want); * key we have. It returns as soon as a path is found or when we run out * of keys; whichever comes sooner. */ -void dofindpath(uint64_t have, uint64_t want, bool html, int count); +void dofindpath(struct onak_dbctx *dbctx, + uint64_t have, uint64_t want, bool html, int count); -struct stats_key *furthestkey(struct stats_key *have); +struct stats_key *furthestkey(struct onak_dbctx *dbctx, struct stats_key *have); #endif /* __STATS_H__ */ diff --git a/wotsap.c b/wotsap.c index 8990787..66dc946 100644 --- a/wotsap.c +++ b/wotsap.c @@ -62,16 +62,17 @@ static struct ll *sortkeyll(struct ll *keys) return newll; } -static void output_key(FILE *names, FILE *keys, uint64_t keyid) +static void output_key(struct onak_dbctx *dbctx, + FILE *names, FILE *keys, uint64_t keyid) { - fprintf(names, "%s\n", config.dbbackend->keyid2uid(keyid)); + fprintf(names, "%s\n", dbctx->keyid2uid(dbctx, keyid)); fprintf(keys, "%c%c%c%c", (int) (keyid >> 24) & 0xFF, (int) (keyid >> 16) & 0xFF, (int) (keyid >> 8) & 0xFF, (int) (keyid ) & 0xFF); } -static void wotsap(uint64_t keyid, char *dir) +static void wotsap(struct onak_dbctx *dbctx, uint64_t keyid, char *dir) { struct ll *pending, *sigll, *sigsave; uint32_t curidx = 0; @@ -125,29 +126,31 @@ static void wotsap(uint64_t keyid, char *dir) } free(tmppath); - config.dbbackend->cached_getkeysigs(keyid); + dbctx->cached_getkeysigs(dbctx, keyid); curkey = findinhash(keyid); curkey->colour = ++curidx; pending = lladd(NULL, curkey); - output_key(names, keys, curkey->keyid); + output_key(dbctx, names, keys, curkey->keyid); while (pending != NULL) { curkey = (struct stats_key *) pending->object; - sigll = config.dbbackend->cached_getkeysigs(curkey->keyid); + sigll = dbctx->cached_getkeysigs(dbctx, curkey->keyid); sigsave = sigll = sortkeyll(sigll); sigcount = 0; while (sigll != NULL) { addkey = (struct stats_key *) sigll->object; if (addkey->colour == 0 && !addkey->revoked) { - uid = config.dbbackend->keyid2uid(addkey->keyid); + uid = dbctx->keyid2uid(dbctx, addkey->keyid); if (uid != NULL) { /* Force it to be loaded so we know if it's revoked */ - config.dbbackend->cached_getkeysigs(addkey->keyid); + dbctx->cached_getkeysigs(dbctx, + addkey->keyid); if (!addkey->revoked) { addkey->colour = ++curidx; pending = lladdend(pending, addkey); - output_key(names, keys, addkey->keyid); + output_key(dbctx, names, keys, + addkey->keyid); } } } @@ -184,6 +187,7 @@ int main(int argc, char *argv[]) int optchar; char *configfile = NULL, *dir = NULL; uint64_t keyid = 0x2DA8B985; + struct onak_dbctx *dbctx; while ((optchar = getopt(argc, argv, "c:")) != -1 ) { switch (optchar) { @@ -199,11 +203,16 @@ int main(int argc, char *argv[]) readconfig(configfile); initlogthing("wotsap", config.logfile); - config.dbbackend->initdb(true); - inithash(); - wotsap(config.dbbackend->getfullkeyid(keyid), dir ? dir : "."); - destroyhash(); - config.dbbackend->cleanupdb(); + dbctx = config.dbinit(true); + if (dbctx != NULL) { + inithash(); + wotsap(dbctx, dbctx->getfullkeyid(dbctx, keyid), + dir ? dir : "."); + destroyhash(); + dbctx->cleanupdb(dbctx); + } else { + fprintf(stderr, "Couldn't initialize key database.\n"); + } cleanuplogthing(); cleanupconfig(); } -- 2.39.2