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.
23 #include "decodekey.h"
27 #include "keystructs.h"
31 #include "onak-conf.h"
36 struct onak_stacked_dbctx {
38 bool store_on_fallback;
42 * The following functions only apply to the first backend.
45 static bool stacked_starttrans(struct onak_dbctx *dbctx)
47 struct onak_stacked_dbctx *privctx =
48 (struct onak_stacked_dbctx *) dbctx->priv;
49 struct onak_dbctx *backend =
50 (struct onak_dbctx *) privctx->backends->object;
52 return backend->starttrans(backend);
55 static void stacked_endtrans(struct onak_dbctx *dbctx)
57 struct onak_stacked_dbctx *privctx =
58 (struct onak_stacked_dbctx *) dbctx->priv;
59 struct onak_dbctx *backend =
60 (struct onak_dbctx *) privctx->backends->object;
62 backend->starttrans(backend);
65 static int stacked_store_key(struct onak_dbctx *dbctx,
66 struct openpgp_publickey *publickey, bool intrans,
69 struct onak_stacked_dbctx *privctx =
70 (struct onak_stacked_dbctx *) dbctx->priv;
71 struct onak_dbctx *backend =
72 (struct onak_dbctx *) privctx->backends->object;
74 return backend->store_key(backend,
75 publickey, intrans, update);
78 static int stacked_delete_key(struct onak_dbctx *dbctx, uint64_t keyid,
81 struct onak_stacked_dbctx *privctx =
82 (struct onak_stacked_dbctx *) dbctx->priv;
83 struct onak_dbctx *backend =
84 (struct onak_dbctx *) privctx->backends->object;
86 return backend->delete_key(backend,
90 static int stacked_update_keys(struct onak_dbctx *dbctx,
91 struct openpgp_publickey **keys, bool sendsync)
93 struct onak_stacked_dbctx *privctx =
94 (struct onak_stacked_dbctx *) dbctx->priv;
95 struct onak_dbctx *backend =
96 (struct onak_dbctx *) privctx->backends->object;
98 return backend->update_keys(backend, keys, sendsync);
101 static int stacked_iterate_keys(struct onak_dbctx *dbctx,
102 void (*iterfunc)(void *ctx, struct openpgp_publickey *key),
105 struct onak_stacked_dbctx *privctx =
106 (struct onak_stacked_dbctx *) dbctx->priv;
107 struct onak_dbctx *backend =
108 (struct onak_dbctx *) privctx->backends->object;
110 return backend->iterate_keys(backend, iterfunc, ctx);
113 static void store_on_fallback(struct onak_stacked_dbctx *privctx,
114 struct openpgp_publickey *publickey, bool intrans)
116 struct onak_dbctx *backend =
117 (struct onak_dbctx *) privctx->backends->object;
118 struct openpgp_publickey *curkey;
121 * If we walked the stack at all, store the key in the first
122 * backend if configured to do so. It's not an update as we
123 * know it's not there or we wouldn't have fallen back.
125 for (curkey = publickey; curkey != NULL; curkey = curkey->next) {
126 backend->store_key(backend, curkey, intrans, false);
131 * The functions below will walk along the backend stack until they
132 * reach the end or get a successful result.
135 static int stacked_fetch_key_id(struct onak_dbctx *dbctx, uint64_t keyid,
136 struct openpgp_publickey **publickey, bool intrans)
138 struct onak_stacked_dbctx *privctx =
139 (struct onak_stacked_dbctx *) dbctx->priv;
140 struct onak_dbctx *backend;
144 for (cur = privctx->backends; cur != NULL && res == 0;
146 backend = (struct onak_dbctx *) cur->object;
147 res = backend->fetch_key_id(backend, keyid, publickey,
151 if (privctx->store_on_fallback && cur != privctx->backends) {
152 store_on_fallback(privctx, *publickey, intrans);
158 static int stacked_fetch_key_fp(struct onak_dbctx *dbctx,
159 struct openpgp_fingerprint *fingerprint,
160 struct openpgp_publickey **publickey, bool intrans)
162 struct onak_stacked_dbctx *privctx =
163 (struct onak_stacked_dbctx *) dbctx->priv;
164 struct onak_dbctx *backend;
168 for (cur = privctx->backends; cur != NULL && res == 0;
170 backend = (struct onak_dbctx *) cur->object;
171 res = backend->fetch_key_fp(backend, fingerprint, publickey,
175 if (privctx->store_on_fallback && cur != privctx->backends) {
176 store_on_fallback(privctx, *publickey, intrans);
182 static int stacked_fetch_key_text(struct onak_dbctx *dbctx,
184 struct openpgp_publickey **publickey)
186 struct onak_stacked_dbctx *privctx =
187 (struct onak_stacked_dbctx *) dbctx->priv;
188 struct onak_dbctx *backend;
192 for (cur = privctx->backends; cur != NULL && res == 0;
194 backend = (struct onak_dbctx *) cur->object;
195 res = backend->fetch_key_text(backend, search, publickey);
198 if (privctx->store_on_fallback && cur != privctx->backends) {
199 store_on_fallback(privctx, *publickey, false);
205 static int stacked_fetch_key_skshash(struct onak_dbctx *dbctx,
206 const struct skshash *hash,
207 struct openpgp_publickey **publickey)
209 struct onak_stacked_dbctx *privctx =
210 (struct onak_stacked_dbctx *) dbctx->priv;
211 struct onak_dbctx *backend;
215 for (cur = privctx->backends; cur != NULL && res == 0;
217 backend = (struct onak_dbctx *) cur->object;
218 res = backend->fetch_key_skshash(backend, hash, publickey);
221 if (privctx->store_on_fallback && cur != privctx->backends) {
222 store_on_fallback(privctx, *publickey, false);
228 static struct ll *stacked_getkeysigs(struct onak_dbctx *dbctx,
229 uint64_t keyid, bool *revoked)
231 struct onak_stacked_dbctx *privctx =
232 (struct onak_stacked_dbctx *) dbctx->priv;
233 struct onak_dbctx *backend;
235 struct ll *res = NULL;
237 for (cur = privctx->backends; cur != NULL && res == NULL;
239 backend = (struct onak_dbctx *) cur->object;
240 res = backend->getkeysigs(backend, keyid, revoked);
246 static struct ll *stacked_cached_getkeysigs(struct onak_dbctx *dbctx,
249 struct onak_stacked_dbctx *privctx =
250 (struct onak_stacked_dbctx *) dbctx->priv;
251 struct onak_dbctx *backend;
253 struct ll *res = NULL;
255 for (cur = privctx->backends; cur != NULL && res == NULL;
257 backend = (struct onak_dbctx *) cur->object;
258 res = backend->cached_getkeysigs(backend, keyid);
264 static char *stacked_keyid2uid(struct onak_dbctx *dbctx,
267 struct onak_stacked_dbctx *privctx =
268 (struct onak_stacked_dbctx *) dbctx->priv;
269 struct onak_dbctx *backend;
273 for (cur = privctx->backends; cur != NULL && res == NULL;
275 backend = (struct onak_dbctx *) cur->object;
276 res = backend->keyid2uid(backend, keyid);
282 static uint64_t stacked_getfullkeyid(struct onak_dbctx *dbctx,
285 struct onak_stacked_dbctx *privctx =
286 (struct onak_stacked_dbctx *) dbctx->priv;
287 struct onak_dbctx *backend;
291 for (cur = privctx->backends; cur != NULL && res == 0;
293 backend = (struct onak_dbctx *) cur->object;
294 res = backend->getfullkeyid(backend, keyid);
300 static void stacked_cleanupdb(struct onak_dbctx *dbctx)
302 struct onak_stacked_dbctx *privctx =
303 (struct onak_stacked_dbctx *) dbctx->priv;
304 struct onak_dbctx *backend;
308 for (cur = privctx->backends; cur != NULL && res == 0;
310 backend = (struct onak_dbctx *) cur->object;
311 backend->cleanupdb(backend);
314 if (dbctx->priv != NULL) {
324 struct onak_dbctx *keydb_stacked_init(struct onak_db_config *dbcfg,
327 struct onak_dbctx *dbctx;
328 struct onak_stacked_dbctx *privctx;
329 struct onak_dbctx *backend;
330 struct onak_db_config *backend_cfg;
331 char *backend_name, *saveptr = NULL;
334 logthing(LOGTHING_CRITICAL,
335 "No backend database configuration supplied.");
339 dbctx = malloc(sizeof(struct onak_dbctx));
345 dbctx->config = dbcfg;
346 dbctx->priv = privctx = malloc(sizeof(struct onak_stacked_dbctx));
347 if (dbctx->priv == NULL) {
352 /* TODO: Make configurable? */
353 privctx->store_on_fallback = true;
354 privctx->backends = NULL;
356 backend_name = strtok_r(dbcfg->location, ":", &saveptr);
357 while (backend_name != NULL) {
358 backend_cfg = find_db_backend_config(config.backends,
360 if (backend_cfg == NULL) {
361 logthing(LOGTHING_CRITICAL,
362 "Couldn't find configuration for %s backend",
364 stacked_cleanupdb(dbctx);
367 logthing(LOGTHING_INFO, "Loading stacked backend: %s",
370 backend = config.dbinit(backend_cfg, readonly);
371 privctx->backends = lladdend(privctx->backends, backend);
373 backend_name = strtok_r(NULL, ":", &saveptr);
376 if (privctx->backends != NULL) {
377 dbctx->cleanupdb = stacked_cleanupdb;
378 dbctx->starttrans = stacked_starttrans;
379 dbctx->endtrans = stacked_endtrans;
380 dbctx->fetch_key_id = stacked_fetch_key_id;
381 dbctx->fetch_key_fp = stacked_fetch_key_fp;
382 dbctx->fetch_key_text = stacked_fetch_key_text;
383 dbctx->fetch_key_skshash = stacked_fetch_key_skshash;
384 dbctx->store_key = stacked_store_key;
385 dbctx->update_keys = stacked_update_keys;
386 dbctx->delete_key = stacked_delete_key;
387 dbctx->getkeysigs = stacked_getkeysigs;
388 dbctx->cached_getkeysigs = stacked_cached_getkeysigs;
389 dbctx->keyid2uid = stacked_keyid2uid;
390 dbctx->getfullkeyid = stacked_getfullkeyid;
391 dbctx->iterate_keys = stacked_iterate_keys;