2 * keydb_stacked.c - backend that stacks other backends together
4 * Copyright 2016 Jonathan McDowell <noodles@earth.li>
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; version 2 of the License.
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 51
17 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 #include "decodekey.h"
28 #include "keystructs.h"
32 #include "onak-conf.h"
37 struct onak_stacked_dbctx {
39 bool store_on_fallback;
43 * The following functions only apply to the first backend.
46 static bool stacked_starttrans(struct onak_dbctx *dbctx)
48 struct onak_stacked_dbctx *privctx =
49 (struct onak_stacked_dbctx *) dbctx->priv;
50 struct onak_dbctx *backend =
51 (struct onak_dbctx *) privctx->backends->object;
53 return backend->starttrans(backend);
56 static void stacked_endtrans(struct onak_dbctx *dbctx)
58 struct onak_stacked_dbctx *privctx =
59 (struct onak_stacked_dbctx *) dbctx->priv;
60 struct onak_dbctx *backend =
61 (struct onak_dbctx *) privctx->backends->object;
63 backend->starttrans(backend);
66 static int stacked_store_key(struct onak_dbctx *dbctx,
67 struct openpgp_publickey *publickey, bool intrans,
70 struct onak_stacked_dbctx *privctx =
71 (struct onak_stacked_dbctx *) dbctx->priv;
72 struct onak_dbctx *backend =
73 (struct onak_dbctx *) privctx->backends->object;
75 return backend->store_key(backend,
76 publickey, intrans, update);
79 static int stacked_delete_key(struct onak_dbctx *dbctx, uint64_t keyid,
82 struct onak_stacked_dbctx *privctx =
83 (struct onak_stacked_dbctx *) dbctx->priv;
84 struct onak_dbctx *backend =
85 (struct onak_dbctx *) privctx->backends->object;
87 return backend->delete_key(backend,
91 static int stacked_update_keys(struct onak_dbctx *dbctx,
92 struct openpgp_publickey **keys, bool sendsync)
94 struct onak_stacked_dbctx *privctx =
95 (struct onak_stacked_dbctx *) dbctx->priv;
96 struct onak_dbctx *backend =
97 (struct onak_dbctx *) privctx->backends->object;
99 return backend->update_keys(backend, keys, sendsync);
102 static int stacked_iterate_keys(struct onak_dbctx *dbctx,
103 void (*iterfunc)(void *ctx, struct openpgp_publickey *key),
106 struct onak_stacked_dbctx *privctx =
107 (struct onak_stacked_dbctx *) dbctx->priv;
108 struct onak_dbctx *backend =
109 (struct onak_dbctx *) privctx->backends->object;
111 return backend->iterate_keys(backend, iterfunc, ctx);
114 static void store_on_fallback(struct onak_stacked_dbctx *privctx,
115 struct openpgp_publickey *publickey, bool intrans)
117 struct onak_dbctx *backend =
118 (struct onak_dbctx *) privctx->backends->object;
119 struct openpgp_publickey *curkey;
121 cleankeys(publickey);
123 * If we walked the stack at all, store the key in the first
124 * backend if configured to do so. It's not an update as we
125 * know it's not there or we wouldn't have fallen back.
127 for (curkey = publickey; curkey != NULL; curkey = curkey->next) {
128 backend->store_key(backend, curkey, intrans, false);
133 * The functions below will walk along the backend stack until they
134 * reach the end or get a successful result.
137 static int stacked_fetch_key_id(struct onak_dbctx *dbctx, uint64_t keyid,
138 struct openpgp_publickey **publickey, bool intrans)
140 struct onak_stacked_dbctx *privctx =
141 (struct onak_stacked_dbctx *) dbctx->priv;
142 struct onak_dbctx *backend;
146 for (cur = privctx->backends; cur != NULL && res == 0;
148 backend = (struct onak_dbctx *) cur->object;
149 res = backend->fetch_key_id(backend, keyid, publickey,
153 if (privctx->store_on_fallback && cur != privctx->backends) {
154 store_on_fallback(privctx, *publickey, intrans);
160 static int stacked_fetch_key_fp(struct onak_dbctx *dbctx,
161 struct openpgp_fingerprint *fingerprint,
162 struct openpgp_publickey **publickey, bool intrans)
164 struct onak_stacked_dbctx *privctx =
165 (struct onak_stacked_dbctx *) dbctx->priv;
166 struct onak_dbctx *backend;
170 for (cur = privctx->backends; cur != NULL && res == 0;
172 backend = (struct onak_dbctx *) cur->object;
173 res = backend->fetch_key_fp(backend, fingerprint, publickey,
177 if (privctx->store_on_fallback && cur != privctx->backends) {
178 store_on_fallback(privctx, *publickey, intrans);
184 static int stacked_fetch_key_text(struct onak_dbctx *dbctx,
186 struct openpgp_publickey **publickey)
188 struct onak_stacked_dbctx *privctx =
189 (struct onak_stacked_dbctx *) dbctx->priv;
190 struct onak_dbctx *backend;
194 for (cur = privctx->backends; cur != NULL && res == 0;
196 backend = (struct onak_dbctx *) cur->object;
197 res = backend->fetch_key_text(backend, search, publickey);
200 if (privctx->store_on_fallback && cur != privctx->backends) {
201 store_on_fallback(privctx, *publickey, false);
207 static int stacked_fetch_key_skshash(struct onak_dbctx *dbctx,
208 const struct skshash *hash,
209 struct openpgp_publickey **publickey)
211 struct onak_stacked_dbctx *privctx =
212 (struct onak_stacked_dbctx *) dbctx->priv;
213 struct onak_dbctx *backend;
217 for (cur = privctx->backends; cur != NULL && res == 0;
219 backend = (struct onak_dbctx *) cur->object;
220 res = backend->fetch_key_skshash(backend, hash, publickey);
223 if (privctx->store_on_fallback && cur != privctx->backends) {
224 store_on_fallback(privctx, *publickey, false);
230 static struct ll *stacked_getkeysigs(struct onak_dbctx *dbctx,
231 uint64_t keyid, bool *revoked)
233 struct onak_stacked_dbctx *privctx =
234 (struct onak_stacked_dbctx *) dbctx->priv;
235 struct onak_dbctx *backend;
237 struct ll *res = NULL;
239 for (cur = privctx->backends; cur != NULL && res == NULL;
241 backend = (struct onak_dbctx *) cur->object;
242 res = backend->getkeysigs(backend, keyid, revoked);
248 static struct ll *stacked_cached_getkeysigs(struct onak_dbctx *dbctx,
251 struct onak_stacked_dbctx *privctx =
252 (struct onak_stacked_dbctx *) dbctx->priv;
253 struct onak_dbctx *backend;
255 struct ll *res = NULL;
257 for (cur = privctx->backends; cur != NULL && res == NULL;
259 backend = (struct onak_dbctx *) cur->object;
260 res = backend->cached_getkeysigs(backend, keyid);
266 static char *stacked_keyid2uid(struct onak_dbctx *dbctx,
269 struct onak_stacked_dbctx *privctx =
270 (struct onak_stacked_dbctx *) dbctx->priv;
271 struct onak_dbctx *backend;
275 for (cur = privctx->backends; cur != NULL && res == NULL;
277 backend = (struct onak_dbctx *) cur->object;
278 res = backend->keyid2uid(backend, keyid);
284 static uint64_t stacked_getfullkeyid(struct onak_dbctx *dbctx,
287 struct onak_stacked_dbctx *privctx =
288 (struct onak_stacked_dbctx *) dbctx->priv;
289 struct onak_dbctx *backend;
293 for (cur = privctx->backends; cur != NULL && res == 0;
295 backend = (struct onak_dbctx *) cur->object;
296 res = backend->getfullkeyid(backend, keyid);
302 static void stacked_cleanupdb(struct onak_dbctx *dbctx)
304 struct onak_stacked_dbctx *privctx =
305 (struct onak_stacked_dbctx *) dbctx->priv;
306 struct onak_dbctx *backend;
310 for (cur = privctx->backends; cur != NULL && res == 0;
312 backend = (struct onak_dbctx *) cur->object;
313 backend->cleanupdb(backend);
316 if (dbctx->priv != NULL) {
326 struct onak_dbctx *keydb_stacked_init(struct onak_db_config *dbcfg,
329 struct onak_dbctx *dbctx;
330 struct onak_stacked_dbctx *privctx;
331 struct onak_dbctx *backend;
332 struct onak_db_config *backend_cfg;
333 char *backend_name, *saveptr = NULL;
336 logthing(LOGTHING_CRITICAL,
337 "No backend database configuration supplied.");
341 dbctx = malloc(sizeof(struct onak_dbctx));
347 dbctx->config = dbcfg;
348 dbctx->priv = privctx = malloc(sizeof(struct onak_stacked_dbctx));
349 if (dbctx->priv == NULL) {
354 /* TODO: Make configurable? */
355 privctx->store_on_fallback = true;
356 privctx->backends = NULL;
358 backend_name = strtok_r(dbcfg->location, ":", &saveptr);
359 while (backend_name != NULL) {
360 backend_cfg = find_db_backend_config(config.backends,
362 if (backend_cfg == NULL) {
363 logthing(LOGTHING_CRITICAL,
364 "Couldn't find configuration for %s backend",
366 stacked_cleanupdb(dbctx);
369 logthing(LOGTHING_INFO, "Loading stacked backend: %s",
372 backend = config.dbinit(backend_cfg, readonly);
373 privctx->backends = lladdend(privctx->backends, backend);
375 backend_name = strtok_r(NULL, ":", &saveptr);
378 if (privctx->backends != NULL) {
379 dbctx->cleanupdb = stacked_cleanupdb;
380 dbctx->starttrans = stacked_starttrans;
381 dbctx->endtrans = stacked_endtrans;
382 dbctx->fetch_key_id = stacked_fetch_key_id;
383 dbctx->fetch_key_fp = stacked_fetch_key_fp;
384 dbctx->fetch_key_text = stacked_fetch_key_text;
385 dbctx->fetch_key_skshash = stacked_fetch_key_skshash;
386 dbctx->store_key = stacked_store_key;
387 dbctx->update_keys = stacked_update_keys;
388 dbctx->delete_key = stacked_delete_key;
389 dbctx->getkeysigs = stacked_getkeysigs;
390 dbctx->cached_getkeysigs = stacked_cached_getkeysigs;
391 dbctx->keyid2uid = stacked_keyid2uid;
392 dbctx->getfullkeyid = stacked_getfullkeyid;
393 dbctx->iterate_keys = stacked_iterate_keys;