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, see <https://www.gnu.org/licenses/>.
27 #include "keystructs.h"
30 #include "onak-conf.h"
32 struct onak_stacked_dbctx {
34 bool store_on_fallback;
38 * The following functions only apply to the first backend.
41 static bool stacked_starttrans(struct onak_dbctx *dbctx)
43 struct onak_stacked_dbctx *privctx =
44 (struct onak_stacked_dbctx *) dbctx->priv;
45 struct onak_dbctx *backend =
46 (struct onak_dbctx *) privctx->backends->object;
48 return backend->starttrans(backend);
51 static void stacked_endtrans(struct onak_dbctx *dbctx)
53 struct onak_stacked_dbctx *privctx =
54 (struct onak_stacked_dbctx *) dbctx->priv;
55 struct onak_dbctx *backend =
56 (struct onak_dbctx *) privctx->backends->object;
58 backend->starttrans(backend);
61 static int stacked_store_key(struct onak_dbctx *dbctx,
62 struct openpgp_publickey *publickey, bool intrans,
65 struct onak_stacked_dbctx *privctx =
66 (struct onak_stacked_dbctx *) dbctx->priv;
67 struct onak_dbctx *backend =
68 (struct onak_dbctx *) privctx->backends->object;
70 return backend->store_key(backend,
71 publickey, intrans, update);
74 static int stacked_delete_key(struct onak_dbctx *dbctx, uint64_t keyid,
77 struct onak_stacked_dbctx *privctx =
78 (struct onak_stacked_dbctx *) dbctx->priv;
79 struct onak_dbctx *backend =
80 (struct onak_dbctx *) privctx->backends->object;
82 return backend->delete_key(backend,
86 static int stacked_update_keys(struct onak_dbctx *dbctx,
87 struct openpgp_publickey **keys, bool sendsync)
89 struct onak_stacked_dbctx *privctx =
90 (struct onak_stacked_dbctx *) dbctx->priv;
91 struct onak_dbctx *backend =
92 (struct onak_dbctx *) privctx->backends->object;
94 return backend->update_keys(backend, keys, sendsync);
97 static int stacked_iterate_keys(struct onak_dbctx *dbctx,
98 void (*iterfunc)(void *ctx, struct openpgp_publickey *key),
101 struct onak_stacked_dbctx *privctx =
102 (struct onak_stacked_dbctx *) dbctx->priv;
103 struct onak_dbctx *backend =
104 (struct onak_dbctx *) privctx->backends->object;
106 return backend->iterate_keys(backend, iterfunc, ctx);
109 static void store_on_fallback(struct onak_stacked_dbctx *privctx,
110 struct openpgp_publickey *publickey, bool intrans)
112 struct onak_dbctx *backend =
113 (struct onak_dbctx *) privctx->backends->object;
114 struct openpgp_publickey *curkey;
116 cleankeys(&publickey, config.clean_policies);
118 * If we walked the stack at all, store the key in the first
119 * backend if configured to do so. It's not an update as we
120 * know it's not there or we wouldn't have fallen back.
122 for (curkey = publickey; curkey != NULL; curkey = curkey->next) {
123 backend->store_key(backend, curkey, intrans, false);
128 * The functions below will walk along the backend stack until they
129 * reach the end or get a successful result.
132 static int stacked_fetch_key_id(struct onak_dbctx *dbctx, uint64_t keyid,
133 struct openpgp_publickey **publickey, bool intrans)
135 struct onak_stacked_dbctx *privctx =
136 (struct onak_stacked_dbctx *) dbctx->priv;
137 struct onak_dbctx *backend;
141 for (cur = privctx->backends; cur != NULL && res == 0;
143 backend = (struct onak_dbctx *) cur->object;
144 res = backend->fetch_key_id(backend, keyid, publickey,
148 if (privctx->store_on_fallback && cur != privctx->backends) {
149 store_on_fallback(privctx, *publickey, intrans);
155 static int stacked_fetch_key_fp(struct onak_dbctx *dbctx,
156 struct openpgp_fingerprint *fingerprint,
157 struct openpgp_publickey **publickey, bool intrans)
159 struct onak_stacked_dbctx *privctx =
160 (struct onak_stacked_dbctx *) dbctx->priv;
161 struct onak_dbctx *backend;
165 for (cur = privctx->backends; cur != NULL && res == 0;
167 backend = (struct onak_dbctx *) cur->object;
168 res = backend->fetch_key_fp(backend, fingerprint, publickey,
172 if (privctx->store_on_fallback && cur != privctx->backends) {
173 store_on_fallback(privctx, *publickey, intrans);
179 static int stacked_fetch_key_text(struct onak_dbctx *dbctx,
181 struct openpgp_publickey **publickey)
183 struct onak_stacked_dbctx *privctx =
184 (struct onak_stacked_dbctx *) dbctx->priv;
185 struct onak_dbctx *backend;
189 for (cur = privctx->backends; cur != NULL && res == 0;
191 backend = (struct onak_dbctx *) cur->object;
192 res = backend->fetch_key_text(backend, search, publickey);
195 if (privctx->store_on_fallback && cur != privctx->backends) {
196 store_on_fallback(privctx, *publickey, false);
202 static int stacked_fetch_key_skshash(struct onak_dbctx *dbctx,
203 const struct skshash *hash,
204 struct openpgp_publickey **publickey)
206 struct onak_stacked_dbctx *privctx =
207 (struct onak_stacked_dbctx *) dbctx->priv;
208 struct onak_dbctx *backend;
212 for (cur = privctx->backends; cur != NULL && res == 0;
214 backend = (struct onak_dbctx *) cur->object;
215 res = backend->fetch_key_skshash(backend, hash, publickey);
218 if (privctx->store_on_fallback && cur != privctx->backends) {
219 store_on_fallback(privctx, *publickey, false);
226 * Include the basic keydb routines so we can use them for fall back.
227 * For all of the following we try the top keydb backend and if that doesn't
228 * have answer fall back to the generics, which will do a retrieve from a
229 * backend further down the stack, then a fallback store.
231 #define NEED_KEYID2UID 1
232 #define NEED_GETKEYSIGS 1
233 #define NEED_GETFULLKEYID 1
234 #define NEED_UPDATEKEYS 1
237 static struct ll *stacked_getkeysigs(struct onak_dbctx *dbctx,
238 uint64_t keyid, bool *revoked)
240 struct onak_stacked_dbctx *privctx =
241 (struct onak_stacked_dbctx *) dbctx->priv;
242 struct onak_dbctx *backend =
243 (struct onak_dbctx *) privctx->backends->object;
246 res = backend->getkeysigs(backend, keyid, revoked);
248 res = generic_getkeysigs(dbctx, keyid, revoked);
254 static struct ll *stacked_cached_getkeysigs(struct onak_dbctx *dbctx,
257 struct onak_stacked_dbctx *privctx =
258 (struct onak_stacked_dbctx *) dbctx->priv;
259 struct onak_dbctx *backend =
260 (struct onak_dbctx *) privctx->backends->object;
263 res = backend->cached_getkeysigs(backend, keyid);
265 res = generic_cached_getkeysigs(dbctx, keyid);
271 static char *stacked_keyid2uid(struct onak_dbctx *dbctx,
274 struct onak_stacked_dbctx *privctx =
275 (struct onak_stacked_dbctx *) dbctx->priv;
276 struct onak_dbctx *backend =
277 (struct onak_dbctx *) privctx->backends->object;
280 res = backend->keyid2uid(backend, keyid);
282 res = generic_keyid2uid(dbctx, keyid);
288 static uint64_t stacked_getfullkeyid(struct onak_dbctx *dbctx,
291 struct onak_stacked_dbctx *privctx =
292 (struct onak_stacked_dbctx *) dbctx->priv;
293 struct onak_dbctx *backend =
294 (struct onak_dbctx *) privctx->backends->object;
297 res = backend->getfullkeyid(backend, keyid);
299 res = generic_getfullkeyid(dbctx, keyid);
305 static void stacked_cleanupdb(struct onak_dbctx *dbctx)
307 struct onak_stacked_dbctx *privctx =
308 (struct onak_stacked_dbctx *) dbctx->priv;
309 struct onak_dbctx *backend;
313 for (cur = privctx->backends; cur != NULL && res == 0;
315 backend = (struct onak_dbctx *) cur->object;
316 backend->cleanupdb(backend);
319 if (dbctx->priv != NULL) {
329 struct onak_dbctx *keydb_stacked_init(struct onak_db_config *dbcfg,
332 struct onak_dbctx *dbctx;
333 struct onak_stacked_dbctx *privctx;
334 struct onak_dbctx *backend;
335 struct onak_db_config *backend_cfg;
336 char *backend_name, *saveptr = NULL;
339 logthing(LOGTHING_CRITICAL,
340 "No backend database configuration supplied.");
344 dbctx = malloc(sizeof(struct onak_dbctx));
350 dbctx->config = dbcfg;
351 dbctx->priv = privctx = malloc(sizeof(struct onak_stacked_dbctx));
352 if (dbctx->priv == NULL) {
357 /* TODO: Make configurable? */
358 privctx->store_on_fallback = true;
359 privctx->backends = NULL;
361 backend_name = strtok_r(dbcfg->location, ":", &saveptr);
362 while (backend_name != NULL) {
363 backend_cfg = find_db_backend_config(config.backends,
365 if (backend_cfg == NULL) {
366 logthing(LOGTHING_CRITICAL,
367 "Couldn't find configuration for %s backend",
369 stacked_cleanupdb(dbctx);
372 logthing(LOGTHING_INFO, "Loading stacked backend: %s",
375 backend = config.dbinit(backend_cfg, readonly);
376 privctx->backends = lladdend(privctx->backends, backend);
378 backend_name = strtok_r(NULL, ":", &saveptr);
381 if (privctx->backends != NULL) {
382 dbctx->cleanupdb = stacked_cleanupdb;
383 dbctx->starttrans = stacked_starttrans;
384 dbctx->endtrans = stacked_endtrans;
385 dbctx->fetch_key_id = stacked_fetch_key_id;
386 dbctx->fetch_key_fp = stacked_fetch_key_fp;
387 dbctx->fetch_key_text = stacked_fetch_key_text;
388 dbctx->fetch_key_skshash = stacked_fetch_key_skshash;
389 dbctx->store_key = stacked_store_key;
390 dbctx->update_keys = stacked_update_keys;
391 dbctx->delete_key = stacked_delete_key;
392 dbctx->getkeysigs = stacked_getkeysigs;
393 dbctx->cached_getkeysigs = stacked_cached_getkeysigs;
394 dbctx->keyid2uid = stacked_keyid2uid;
395 dbctx->getfullkeyid = stacked_getfullkeyid;
396 dbctx->iterate_keys = stacked_iterate_keys;