]> the.earth.li Git - onak.git/blob - keydb/keydb_stacked.c
Provide key_fetch routine that will not search subkey fingerprints
[onak.git] / keydb / keydb_stacked.c
1 /*
2  * keydb_stacked.c - backend that stacks other backends together
3  *
4  * Copyright 2016 Jonathan McDowell <noodles@earth.li>
5  *
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.
9  *
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
13  * more details.
14  *
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/>.
17  */
18
19 #include <stdbool.h>
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include "cleankey.h"
26 #include "keydb.h"
27 #include "keystructs.h"
28 #include "ll.h"
29 #include "log.h"
30 #include "onak-conf.h"
31
32 struct onak_stacked_dbctx {
33         struct ll *backends;
34         bool store_on_fallback;
35 };
36
37 /*
38  * The following functions only apply to the first backend.
39  */
40
41 static bool stacked_starttrans(struct onak_dbctx *dbctx)
42 {
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;
47
48         return backend->starttrans(backend);
49 }
50
51 static void stacked_endtrans(struct onak_dbctx *dbctx)
52 {
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;
57
58         backend->starttrans(backend);
59 }
60
61 static int stacked_store_key(struct onak_dbctx *dbctx,
62                 struct openpgp_publickey *publickey, bool intrans,
63                 bool update)
64 {
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;
69
70         return backend->store_key(backend,
71                         publickey, intrans, update);
72 }
73
74 static int stacked_delete_key(struct onak_dbctx *dbctx,
75                 struct openpgp_fingerprint *fp,
76                 bool intrans)
77 {
78         struct onak_stacked_dbctx *privctx =
79                         (struct onak_stacked_dbctx *) dbctx->priv;
80         struct onak_dbctx *backend =
81                         (struct onak_dbctx *) privctx->backends->object;
82
83         return backend->delete_key(backend,
84                         fp, intrans);
85 }
86
87 static int stacked_update_keys(struct onak_dbctx *dbctx,
88                 struct openpgp_publickey **keys,
89                 struct keyarray *blacklist,
90                 bool updateonly,
91                 bool sendsync)
92 {
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;
97
98         return backend->update_keys(backend, keys, blacklist, updateonly,
99                         sendsync);
100 }
101
102 static int stacked_iterate_keys(struct onak_dbctx *dbctx,
103                 void (*iterfunc)(void *ctx, struct openpgp_publickey *key),
104                 void *ctx)
105 {
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;
110
111         return backend->iterate_keys(backend, iterfunc, ctx);
112 }
113
114 static void store_on_fallback(struct onak_stacked_dbctx *privctx,
115                 struct openpgp_publickey *publickey, bool intrans)
116 {
117         struct onak_dbctx *backend =
118                         (struct onak_dbctx *) privctx->backends->object;
119         struct openpgp_publickey *curkey;
120
121         cleankeys(backend, &publickey, config.clean_policies);
122         /*
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.
126          */
127         for (curkey = publickey; curkey != NULL; curkey = curkey->next) {
128                 backend->store_key(backend, curkey, intrans, false);
129         }
130 }
131
132 /*
133  * The functions below will walk along the backend stack until they
134  * reach the end or get a successful result.
135  */
136
137 static int stacked_fetch_key(struct onak_dbctx *dbctx,
138                 struct openpgp_fingerprint *fingerprint,
139                 struct openpgp_publickey **publickey, bool intrans)
140 {
141         struct onak_stacked_dbctx *privctx =
142                         (struct onak_stacked_dbctx *) dbctx->priv;
143         struct onak_dbctx *backend;
144         struct ll *cur;
145         int res = 0;
146
147         for (cur = privctx->backends; cur != NULL && res == 0;
148                         cur = cur->next) {
149                 backend = (struct onak_dbctx *) cur->object;
150                 res = backend->fetch_key(backend, fingerprint, publickey,
151                                 intrans);
152         }
153
154         if (privctx->store_on_fallback && cur != privctx->backends) {
155                 store_on_fallback(privctx, *publickey, intrans);
156         }
157
158         return res;
159 }
160
161 static int stacked_fetch_key_fp(struct onak_dbctx *dbctx,
162                 struct openpgp_fingerprint *fingerprint,
163                 struct openpgp_publickey **publickey, bool intrans)
164 {
165         struct onak_stacked_dbctx *privctx =
166                         (struct onak_stacked_dbctx *) dbctx->priv;
167         struct onak_dbctx *backend;
168         struct ll *cur;
169         int res = 0;
170
171         for (cur = privctx->backends; cur != NULL && res == 0;
172                         cur = cur->next) {
173                 backend = (struct onak_dbctx *) cur->object;
174                 res = backend->fetch_key_fp(backend, fingerprint, publickey,
175                                 intrans);
176         }
177
178         if (privctx->store_on_fallback && cur != privctx->backends) {
179                 store_on_fallback(privctx, *publickey, intrans);
180         }
181
182         return res;
183 }
184
185 static int stacked_fetch_key_id(struct onak_dbctx *dbctx, uint64_t keyid,
186                 struct openpgp_publickey **publickey, bool intrans)
187 {
188         struct onak_stacked_dbctx *privctx =
189                         (struct onak_stacked_dbctx *) dbctx->priv;
190         struct onak_dbctx *backend;
191         struct ll *cur;
192         int res = 0;
193
194         for (cur = privctx->backends; cur != NULL && res == 0;
195                         cur = cur->next) {
196                 backend = (struct onak_dbctx *) cur->object;
197                 res = backend->fetch_key_id(backend, keyid, publickey,
198                                 intrans);
199         }
200
201         if (privctx->store_on_fallback && cur != privctx->backends) {
202                 store_on_fallback(privctx, *publickey, intrans);
203         }
204
205         return res;
206 }
207
208 static int stacked_fetch_key_text(struct onak_dbctx *dbctx,
209                 const char *search,
210                 struct openpgp_publickey **publickey)
211 {
212         struct onak_stacked_dbctx *privctx =
213                         (struct onak_stacked_dbctx *) dbctx->priv;
214         struct onak_dbctx *backend;
215         struct ll *cur;
216         int res = 0;
217
218         for (cur = privctx->backends; cur != NULL && res == 0;
219                         cur = cur->next) {
220                 backend = (struct onak_dbctx *) cur->object;
221                 res = backend->fetch_key_text(backend, search, publickey);
222         }
223
224         if (privctx->store_on_fallback && cur != privctx->backends) {
225                 store_on_fallback(privctx, *publickey, false);
226         }
227
228         return res;
229 }
230
231 static int stacked_fetch_key_skshash(struct onak_dbctx *dbctx,
232                 const struct skshash *hash,
233                 struct openpgp_publickey **publickey)
234 {
235         struct onak_stacked_dbctx *privctx =
236                         (struct onak_stacked_dbctx *) dbctx->priv;
237         struct onak_dbctx *backend;
238         struct ll *cur;
239         int res = 0;
240
241         for (cur = privctx->backends; cur != NULL && res == 0;
242                         cur = cur->next) {
243                 backend = (struct onak_dbctx *) cur->object;
244                 res = backend->fetch_key_skshash(backend, hash, publickey);
245         }
246
247         if (privctx->store_on_fallback && cur != privctx->backends) {
248                 store_on_fallback(privctx, *publickey, false);
249         }
250
251         return res;
252 }
253
254 /*
255  * Include the basic keydb routines so we can use them for fall back.
256  * For all of the following we try the top keydb backend and if that doesn't
257  * have answer fall back to the generics, which will do a retrieve from a
258  * backend further down the stack, then a fallback store.
259  */
260 #define NEED_KEYID2UID 1
261 #define NEED_GETKEYSIGS 1
262 #define NEED_UPDATEKEYS 1
263 #include "keydb.c"
264
265 static struct ll *stacked_getkeysigs(struct onak_dbctx *dbctx,
266                 uint64_t keyid, bool *revoked)
267 {
268         struct onak_stacked_dbctx *privctx =
269                         (struct onak_stacked_dbctx *) dbctx->priv;
270         struct onak_dbctx *backend =
271                         (struct onak_dbctx *) privctx->backends->object;
272         struct ll *res;
273
274         res = backend->getkeysigs(backend, keyid, revoked);
275         if (res == NULL) {
276                 res = generic_getkeysigs(dbctx, keyid, revoked);
277         }
278
279         return res;
280 }
281
282 static struct ll *stacked_cached_getkeysigs(struct onak_dbctx *dbctx,
283                 uint64_t keyid)
284 {
285         struct onak_stacked_dbctx *privctx =
286                         (struct onak_stacked_dbctx *) dbctx->priv;
287         struct onak_dbctx *backend =
288                         (struct onak_dbctx *) privctx->backends->object;
289         struct ll *res;
290
291         res = backend->cached_getkeysigs(backend, keyid);
292         if (res == NULL) {
293                 res = generic_cached_getkeysigs(dbctx, keyid);
294         }
295
296         return res;
297 }
298
299 static char *stacked_keyid2uid(struct onak_dbctx *dbctx,
300                         uint64_t keyid)
301 {
302         struct onak_stacked_dbctx *privctx =
303                         (struct onak_stacked_dbctx *) dbctx->priv;
304         struct onak_dbctx *backend =
305                         (struct onak_dbctx *) privctx->backends->object;
306         char *res = NULL;
307
308         res = backend->keyid2uid(backend, keyid);
309         if (!res) {
310                 res = generic_keyid2uid(dbctx, keyid);
311         }
312
313         return res;
314 }
315
316 static void stacked_cleanupdb(struct onak_dbctx *dbctx)
317 {
318         struct onak_stacked_dbctx *privctx =
319                         (struct onak_stacked_dbctx *) dbctx->priv;
320         struct onak_dbctx *backend;
321         struct ll *cur;
322         int res = 0;
323
324         for (cur = privctx->backends; cur != NULL && res == 0;
325                         cur = cur->next) {
326                 backend = (struct onak_dbctx *) cur->object;
327                 backend->cleanupdb(backend);
328         }
329
330         if (dbctx->priv != NULL) {
331                 free(dbctx->priv);
332                 dbctx->priv = NULL;
333         }
334
335         if (dbctx != NULL) {
336                 free(dbctx);
337         }
338 }
339
340 struct onak_dbctx *keydb_stacked_init(struct onak_db_config *dbcfg,
341                 bool readonly)
342 {
343         struct onak_dbctx *dbctx;
344         struct onak_stacked_dbctx *privctx;
345         struct onak_dbctx *backend;
346         struct onak_db_config *backend_cfg;
347         char *backend_name, *saveptr = NULL;
348
349         if (dbcfg == NULL) {
350                 logthing(LOGTHING_CRITICAL,
351                         "No backend database configuration supplied.");
352                 return NULL;
353         }
354
355         dbctx = malloc(sizeof(struct onak_dbctx));
356
357         if (dbctx == NULL) {
358                 return NULL;
359         }
360
361         dbctx->config = dbcfg;
362         dbctx->priv = privctx = malloc(sizeof(struct onak_stacked_dbctx));
363         if (dbctx->priv == NULL) {
364                 free(dbctx);
365                 return (NULL);
366         }
367
368         /* TODO: Make configurable? */
369         privctx->store_on_fallback = true;
370         privctx->backends = NULL;
371
372         backend_name = strtok_r(dbcfg->location, ":", &saveptr);
373         while (backend_name != NULL) {
374                 backend_cfg = find_db_backend_config(config.backends,
375                                 backend_name);
376                 if (backend_cfg == NULL) {
377                         logthing(LOGTHING_CRITICAL,
378                                 "Couldn't find configuration for %s backend",
379                                 backend_name);
380                         stacked_cleanupdb(dbctx);
381                         return NULL;
382                 }
383                 logthing(LOGTHING_INFO, "Loading stacked backend: %s",
384                                 backend_cfg->name);
385
386                 backend = config.dbinit(backend_cfg, readonly);
387                 privctx->backends = lladdend(privctx->backends, backend);
388
389                 backend_name = strtok_r(NULL, ":", &saveptr);
390         }
391
392         if (privctx->backends != NULL) {
393                 dbctx->cleanupdb = stacked_cleanupdb;
394                 dbctx->starttrans = stacked_starttrans;
395                 dbctx->endtrans = stacked_endtrans;
396                 dbctx->fetch_key = stacked_fetch_key;
397                 dbctx->fetch_key_fp = stacked_fetch_key_fp;
398                 dbctx->fetch_key_id = stacked_fetch_key_id;
399                 dbctx->fetch_key_text = stacked_fetch_key_text;
400                 dbctx->fetch_key_skshash = stacked_fetch_key_skshash;
401                 dbctx->store_key = stacked_store_key;
402                 dbctx->update_keys = stacked_update_keys;
403                 dbctx->delete_key = stacked_delete_key;
404                 dbctx->getkeysigs = stacked_getkeysigs;
405                 dbctx->cached_getkeysigs = stacked_cached_getkeysigs;
406                 dbctx->keyid2uid = stacked_keyid2uid;
407                 dbctx->iterate_keys = stacked_iterate_keys;
408         }
409
410         return dbctx;
411 }