X-Git-Url: https://the.earth.li/gitweb/?a=blobdiff_plain;f=keydb_dynamic.c;h=9e4e3bcb7585e27decf07aa2a8ca22905d0a0573;hb=adc800dbc424a1e246dd4a82a0c2e88eeda25531;hp=f12889c24afc8d37fa3f36236eecfd878d65e626;hpb=91a98f43c64a6f8c76efb78b8301efaf9c6db1fe;p=onak.git diff --git a/keydb_dynamic.c b/keydb_dynamic.c index f12889c..9e4e3bc 100644 --- a/keydb_dynamic.c +++ b/keydb_dynamic.c @@ -1,536 +1,318 @@ /* * keydb_dynamic.c - backend that can load the other backends * - * Brett Parker + * Copyright 2005 Brett Parker * - * Copyright 2005 Project Purple + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . */ +#include #include +#include #include "decodekey.h" #include "hash.h" #include "keydb.h" #include "keyid.h" #include "keystructs.h" +#include "log.h" #include "mem.h" #include "merge.h" +#include "onak-conf.h" +#include "openpgp.h" #include "parsekey.h" #include "sendsync.h" -#include "keydb_dynamic.h" -struct dynamic_backend *get_backend(void) -{ - return &__dynamicdb_backend__; -} +struct onak_dynamic_dbctx { + struct onak_dbctx *loadeddbctx; + void *backend_handle; +}; -bool backend_loaded(void) +static bool dynamic_starttrans(struct onak_dbctx *dbctx) { - return __dynamicdb_backend__.loaded; + struct onak_dynamic_dbctx *privctx = + (struct onak_dynamic_dbctx *) dbctx->priv; + + return privctx->loadeddbctx->starttrans(privctx->loadeddbctx); } -bool load_backend(void) +static void dynamic_endtrans(struct onak_dbctx *dbctx) { - char *soname = NULL; - void *handle; - struct dynamic_backend *backend = get_backend(); + struct onak_dynamic_dbctx *privctx = + (struct onak_dynamic_dbctx *) dbctx->priv; - if (backend->loaded) { - close_backend(); - } - - 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); + privctx->loadeddbctx->endtrans(privctx->loadeddbctx); +} - handle = dlopen(soname, RTLD_LAZY); - if (handle == NULL) { - logthing(LOGTHING_ERROR, - "Failed to open handle to library '%s': %s", - soname, dlerror()); - free(soname); - soname = NULL; - return false; - } - free(soname); - soname = NULL; +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; - backend->initdb = (initdbfunc_t) dlsym(handle, "initdb"); - backend->cleanupdb = (cleanupdbfunc_t) dlsym(handle, "cleanupdb"); - backend->starttrans = (starttransfunc_t) dlsym(handle, "starttrans"); - backend->endtrans = (endtransfunc_t) dlsym(handle, "endtrans"); - backend->fetch_key = (fetch_keyfunc_t) dlsym(handle, "fetch_key"); - backend->store_key = (store_keyfunc_t) dlsym(handle, "store_key"); - backend->delete_key = (delete_keyfunc_t) dlsym(handle, "delete_key"); - backend->fetch_key_text = (fetch_key_textfunc_t) - dlsym (handle, "fetch_key_text"); - backend->update_keys = (update_keysfunc_t) - dlsym(handle, "update_keys"); - backend->keyid2uid = (keyid2uidfunc_t) dlsym(handle, "keyid2uid"); - backend->cached_getkeysigs = (cached_getkeysigsfunc_t) - dlsym(handle, "cached_getkeysigs"); - backend->getfullkeyid = (getfullkeyidfunc_t) - dlsym(handle, "getfullkeyid"); - backend->iterate_keys = (iterate_keysfunc_t) - dlsym(handle, "iterate_keys"); - - backend->handle = handle; - backend->loaded = true; - - return true; + return privctx->loadeddbctx->fetch_key_id(privctx->loadeddbctx, keyid, + publickey, intrans); } -bool close_backend(void) +static int dynamic_fetch_key_fp(struct onak_dbctx *dbctx, + struct openpgp_fingerprint *fingerprint, + struct openpgp_publickey **publickey, bool intrans) { - struct dynamic_backend *backend; - backend = get_backend(); - - backend->initdb = NULL; - backend->cleanupdb = NULL; - backend->starttrans = NULL; - backend->endtrans = NULL; - backend->fetch_key = NULL; - backend->store_key = NULL; - backend->delete_key = NULL; - backend->fetch_key_text = NULL; - backend->update_keys = NULL; - backend->keyid2uid = NULL; - backend->cached_getkeysigs = NULL; - backend->getfullkeyid = NULL; - backend->iterate_keys = NULL; - backend->loaded = false; - dlclose(backend->handle); - backend->handle = NULL; - - return true; + struct onak_dynamic_dbctx *privctx = + (struct onak_dynamic_dbctx *) dbctx->priv; + + return privctx->loadeddbctx->fetch_key_fp(privctx->loadeddbctx, + fingerprint, publickey, intrans); } -/** - * keyid2uid - Takes a keyid and returns the primary UID for it. - * @keyid: The keyid to lookup. - */ -char *keyid2uid(uint64_t keyid) +static int dynamic_fetch_key_text(struct onak_dbctx *dbctx, + const char *search, + struct openpgp_publickey **publickey) { - 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; - struct dynamic_backend *backend; - if (!backend_loaded()) { - load_backend(); - } - - if (backend_loaded()) { - backend = get_backend(); - if (backend->keyid2uid != NULL) { - return backend->keyid2uid(keyid); - } - } - - buf[0]=0; - if (fetch_key(keyid, &publickey, false) && publickey != NULL) { - curuid = publickey->uids; - while (curuid != NULL && buf[0] == 0) { - if (curuid->packet->tag == 13) { - 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); - } + return privctx->loadeddbctx->fetch_key_text(privctx->loadeddbctx, + search, publickey); } -/** - * 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. - */ -struct ll *getkeysigs(uint64_t keyid, bool *revoked) +static int dynamic_fetch_key_skshash(struct onak_dbctx *dbctx, + const struct skshash *hash, + struct openpgp_publickey **publickey) { - struct ll *sigs = NULL; - struct openpgp_signedpacket_list *uids = NULL; - struct openpgp_publickey *publickey = NULL; - - struct dynamic_backend *backend; - if ( !backend_loaded() ) { - load_backend(); - } - - if (backend_loaded()) { - backend = get_backend(); - if (backend->getkeysigs != NULL) { - return backend->getkeysigs(keyid,revoked); - } - } + struct onak_dynamic_dbctx *privctx = + (struct onak_dynamic_dbctx *) dbctx->priv; - fetch_key(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->revocations != NULL); - } - free_publickey(publickey); - } - - return sigs; + return privctx->loadeddbctx->fetch_key_skshash(privctx->loadeddbctx, + hash, publickey); } -/** - * 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. - */ -struct ll *cached_getkeysigs(uint64_t keyid) +static int dynamic_store_key(struct onak_dbctx *dbctx, + struct openpgp_publickey *publickey, bool intrans, + bool update) { - struct stats_key *key = NULL; - struct stats_key *signedkey = NULL; - struct ll *cursig = NULL; - bool revoked = false; - - struct dynamic_backend *backend; - - if (keyid == 0) { - return NULL; - } - - if (!backend_loaded()) { - load_backend(); - } - - if (backend_loaded()) { - backend = get_backend(); - if (backend->cached_getkeysigs != NULL) { - return backend->cached_getkeysigs(keyid); - } - } + struct onak_dynamic_dbctx *privctx = + (struct onak_dynamic_dbctx *) dbctx->priv; - key = createandaddtohash(keyid); + return privctx->loadeddbctx->store_key(privctx->loadeddbctx, + publickey, intrans, update); +} - if (key->gotsigs == false) { - key->sigs = 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; - } +static int dynamic_delete_key(struct onak_dbctx *dbctx, uint64_t keyid, + bool intrans) +{ + struct onak_dynamic_dbctx *privctx = + (struct onak_dynamic_dbctx *) dbctx->priv; - return key->sigs; + return privctx->loadeddbctx->delete_key(privctx->loadeddbctx, + keyid, intrans); } -/** - * 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. - */ -uint64_t getfullkeyid(uint64_t keyid) +static int dynamic_update_keys(struct onak_dbctx *dbctx, + struct openpgp_publickey **keys, bool sendsync) { - struct openpgp_publickey *publickey = NULL; - struct dynamic_backend *backend; - - if (!backend_loaded()) { - load_backend(); - } - - if (backend_loaded()) { - backend = get_backend(); - if (backend->getfullkeyid != NULL) { - return backend->getfullkeyid(keyid); - } - } + struct onak_dynamic_dbctx *privctx = + (struct onak_dynamic_dbctx *) dbctx->priv; - if (keyid < 0x100000000LL) { - fetch_key(keyid, &publickey, false); - if (publickey != NULL) { - keyid = get_keyid(publickey); - free_publickey(publickey); - publickey = NULL; - } else { - keyid = 0; - } - } - - return keyid; + return privctx->loadeddbctx->update_keys(privctx->loadeddbctx, + keys, sendsync); } -/** - * 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. - */ -int update_keys(struct openpgp_publickey **keys, bool sendsync) +static struct ll *dynamic_getkeysigs(struct onak_dbctx *dbctx, + uint64_t keyid, bool *revoked) { - struct openpgp_publickey *curkey = NULL; - struct openpgp_publickey *oldkey = NULL; - struct openpgp_publickey *prev = NULL; - struct dynamic_backend *backend; - int newkeys = 0; - bool intrans; - - if (!backend_loaded()) { - load_backend(); - } - - if (backend_loaded()) { - backend = get_backend(); - if (backend->update_keys != NULL) { - return backend->update_keys(keys, sendsync); - } - } + struct onak_dynamic_dbctx *privctx = + (struct onak_dynamic_dbctx *) dbctx->priv; - for (curkey = *keys; curkey != NULL; curkey = curkey->next) { - intrans = starttrans(); - logthing(LOGTHING_INFO, - "Fetching key 0x%llX, result: %d", - get_keyid(curkey), - fetch_key(get_keyid(curkey), &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->revocations == 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."); - store_key(oldkey, intrans, true); - } - free_publickey(oldkey); - oldkey = NULL; - - } else { - logthing(LOGTHING_INFO, - "Storing completely new key."); - store_key(curkey, intrans, false); - newkeys++; - } - endtrans(); - intrans = false; - } + return privctx->loadeddbctx->getkeysigs(privctx->loadeddbctx, + keyid, revoked); +} - if (sendsync && keys != NULL) { - sendkeysync(*keys); - } +static struct ll *dynamic_cached_getkeysigs(struct onak_dbctx *dbctx, + uint64_t keyid) +{ + struct onak_dynamic_dbctx *privctx = + (struct onak_dynamic_dbctx *) dbctx->priv; - return newkeys; + return privctx->loadeddbctx->cached_getkeysigs(privctx->loadeddbctx, + keyid); } -void initdb(bool readonly) +static char *dynamic_keyid2uid(struct onak_dbctx *dbctx, + uint64_t keyid) { - struct dynamic_backend *backend; - backend = get_backend(); - - if (!backend_loaded()) { - load_backend(); - } + struct onak_dynamic_dbctx *privctx = + (struct onak_dynamic_dbctx *) dbctx->priv; - if (backend->loaded) { - if (backend->initdb != NULL) { - backend->initdb(readonly); - } - } + return privctx->loadeddbctx->keyid2uid(privctx->loadeddbctx, + keyid); } -void cleanupdb(void) +static uint64_t dynamic_getfullkeyid(struct onak_dbctx *dbctx, + uint64_t keyid) { - struct dynamic_backend *backend; - backend = get_backend(); - - if (backend->loaded) { - if (backend->cleanupdb != NULL) { - backend->cleanupdb(); - } - } + struct onak_dynamic_dbctx *privctx = + (struct onak_dynamic_dbctx *) dbctx->priv; - close_backend(); + return privctx->loadeddbctx->getfullkeyid(privctx->loadeddbctx, keyid); } -bool starttrans() +static int dynamic_iterate_keys(struct onak_dbctx *dbctx, + void (*iterfunc)(void *ctx, struct openpgp_publickey *key), + void *ctx) { - struct dynamic_backend *backend; - backend = get_backend(); + struct onak_dynamic_dbctx *privctx = + (struct onak_dynamic_dbctx *) dbctx->priv; - if (!backend_loaded()) { - load_backend(); - } - - if (backend->loaded) { - if (backend->starttrans != NULL) { - return backend->starttrans(); - } - } - - return false; + return privctx->loadeddbctx->iterate_keys(privctx->loadeddbctx, + iterfunc, ctx); } -void endtrans() +static void dynamic_cleanupdb(struct onak_dbctx *dbctx) { - struct dynamic_backend *backend; - backend = get_backend(); + struct onak_dynamic_dbctx *privctx = + (struct onak_dynamic_dbctx *) dbctx->priv; - if (!backend_loaded()) { - load_backend(); - } - - if (backend->loaded) { - if (backend->endtrans != NULL) { - backend->endtrans(); + if (privctx->loadeddbctx != NULL) { + if (privctx->loadeddbctx->cleanupdb != NULL) { + privctx->loadeddbctx->cleanupdb(privctx->loadeddbctx); + privctx->loadeddbctx = NULL; } } -} -int fetch_key(uint64_t keyid, struct openpgp_publickey **publickey, - bool intrans) -{ - struct dynamic_backend *backend; - backend = get_backend(); - - if (!backend_loaded()) { - load_backend(); + if (privctx->backend_handle != NULL) { + dlclose(privctx->backend_handle); + privctx->backend_handle = NULL; } - - if (backend->loaded) { - if (backend->fetch_key != NULL) { - return backend->fetch_key(keyid,publickey,intrans); - } + + if (dbctx->priv != NULL) { + free(dbctx->priv); + dbctx->priv = NULL; } - return -1; + if (dbctx != NULL) { + free(dbctx); + } } -int store_key(struct openpgp_publickey *publickey, bool intrans, bool update) +struct onak_dbctx *keydb_dynamic_init(struct onak_db_config *dbcfg, + bool readonly) { - struct dynamic_backend *backend; - backend = get_backend(); - - if (!backend_loaded()) { - load_backend(); - } - - if (backend->loaded) { - if (backend->store_key != NULL) { - return backend->store_key(publickey,intrans,update); - } + struct onak_dbctx *dbctx; + char *soname; + char *initname; + struct onak_dbctx *(*backend_init)(struct onak_db_config *, bool); + struct onak_dynamic_dbctx *privctx; + char *type; + + if (dbcfg == NULL) { + logthing(LOGTHING_CRITICAL, + "No backend database configuration supplied."); + return NULL; } - return -1; -} + dbctx = malloc(sizeof(struct onak_dbctx)); -int delete_key(uint64_t keyid, bool intrans) -{ - struct dynamic_backend *backend; - backend = get_backend(); + if (dbctx == NULL) { + return NULL; + } - if (!backend_loaded()) { - load_backend(); + dbctx->config = dbcfg; + dbctx->priv = privctx = malloc(sizeof(struct onak_dynamic_dbctx)); + if (dbctx->priv == NULL) { + free(dbctx); + return (NULL); } - - if (backend->loaded) { - if (backend->delete_key != NULL) { - return backend->delete_key(keyid, intrans); - } + + type = dbcfg->type; + if (config.use_keyd) { + type = "keyd"; } - return -1; -} + if (!config.db_backend) { + logthing(LOGTHING_CRITICAL, "No database backend defined."); + exit(EXIT_FAILURE); + } -int fetch_key_text(const char *search, struct openpgp_publickey **publickey) -{ - struct dynamic_backend *backend; - backend = get_backend(); + if (config.backends_dir == NULL) { + soname = malloc(strlen(type) + + strlen("./libkeydb_") + + strlen(".so") + + 1); - if (!backend_loaded()) { - load_backend(); + sprintf(soname, "./libkeydb_%s.so", type); + } else { + soname = malloc(strlen(type) + + strlen("/libkeydb_") + + strlen(".so") + + strlen(config.backends_dir) + + 1); + + sprintf(soname, "%s/libkeydb_%s.so", config.backends_dir, + type); } - - if (backend->loaded) { - if (backend->fetch_key_text != NULL) { - return backend->fetch_key_text(search, publickey); - } + + logthing(LOGTHING_INFO, "Loading dynamic backend: %s", soname); + + 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); } - return -1; -} + initname = malloc(strlen(config.db_backend) + + strlen("keydb_") + + strlen("_init") + + 1); + sprintf(initname, "keydb_%s_init", type); -int iterate_keys(void (*iterfunc)(void *ctx, struct openpgp_publickey *key), - void *ctx) -{ - struct dynamic_backend *backend; - backend = get_backend(); + *(void **) (&backend_init) = dlsym(privctx->backend_handle, initname); + free(initname); - if (!backend_loaded()) { - load_backend(); - } - - if (backend->loaded) { - if (backend->iterate_keys != NULL) { - return backend->iterate_keys(iterfunc, ctx); - } + 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; - return -1; + privctx->loadeddbctx = backend_init(dbcfg, 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; }