]> the.earth.li Git - onak.git/blob - keydb_stacked.c
Add ability to drop overly large packets
[onak.git] / 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, uint64_t keyid,
75                 bool intrans)
76 {
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;
81
82         return backend->delete_key(backend,
83                         keyid, intrans);
84 }
85
86 static int stacked_update_keys(struct onak_dbctx *dbctx,
87                 struct openpgp_publickey **keys, bool sendsync)
88 {
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;
93
94         return backend->update_keys(backend, keys, sendsync);
95 }
96
97 static int stacked_iterate_keys(struct onak_dbctx *dbctx,
98                 void (*iterfunc)(void *ctx, struct openpgp_publickey *key),
99                 void *ctx)
100 {
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;
105
106         return backend->iterate_keys(backend, iterfunc, ctx);
107 }
108
109 static void store_on_fallback(struct onak_stacked_dbctx *privctx,
110                 struct openpgp_publickey *publickey, bool intrans)
111 {
112         struct onak_dbctx *backend =
113                         (struct onak_dbctx *) privctx->backends->object;
114         struct openpgp_publickey *curkey;
115
116         cleankeys(&publickey, config.clean_policies);
117         /*
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.
121          */
122         for (curkey = publickey; curkey != NULL; curkey = curkey->next) {
123                 backend->store_key(backend, curkey, intrans, false);
124         }
125 }
126
127 /*
128  * The functions below will walk along the backend stack until they
129  * reach the end or get a successful result.
130  */
131
132 static int stacked_fetch_key_id(struct onak_dbctx *dbctx, uint64_t keyid,
133                 struct openpgp_publickey **publickey, bool intrans)
134 {
135         struct onak_stacked_dbctx *privctx =
136                         (struct onak_stacked_dbctx *) dbctx->priv;
137         struct onak_dbctx *backend;
138         struct ll *cur;
139         int res = 0;
140
141         for (cur = privctx->backends; cur != NULL && res == 0;
142                         cur = cur->next) {
143                 backend = (struct onak_dbctx *) cur->object;
144                 res = backend->fetch_key_id(backend, keyid, publickey,
145                                 intrans);
146         }
147
148         if (privctx->store_on_fallback && cur != privctx->backends) {
149                 store_on_fallback(privctx, *publickey, intrans);
150         }
151
152         return res;
153 }
154
155 static int stacked_fetch_key_fp(struct onak_dbctx *dbctx,
156                 struct openpgp_fingerprint *fingerprint,
157                 struct openpgp_publickey **publickey, bool intrans)
158 {
159         struct onak_stacked_dbctx *privctx =
160                         (struct onak_stacked_dbctx *) dbctx->priv;
161         struct onak_dbctx *backend;
162         struct ll *cur;
163         int res = 0;
164
165         for (cur = privctx->backends; cur != NULL && res == 0;
166                         cur = cur->next) {
167                 backend = (struct onak_dbctx *) cur->object;
168                 res = backend->fetch_key_fp(backend, fingerprint, publickey,
169                                 intrans);
170         }
171
172         if (privctx->store_on_fallback && cur != privctx->backends) {
173                 store_on_fallback(privctx, *publickey, intrans);
174         }
175
176         return res;
177 }
178
179 static int stacked_fetch_key_text(struct onak_dbctx *dbctx,
180                 const char *search,
181                 struct openpgp_publickey **publickey)
182 {
183         struct onak_stacked_dbctx *privctx =
184                         (struct onak_stacked_dbctx *) dbctx->priv;
185         struct onak_dbctx *backend;
186         struct ll *cur;
187         int res = 0;
188
189         for (cur = privctx->backends; cur != NULL && res == 0;
190                         cur = cur->next) {
191                 backend = (struct onak_dbctx *) cur->object;
192                 res = backend->fetch_key_text(backend, search, publickey);
193         }
194
195         if (privctx->store_on_fallback && cur != privctx->backends) {
196                 store_on_fallback(privctx, *publickey, false);
197         }
198
199         return res;
200 }
201
202 static int stacked_fetch_key_skshash(struct onak_dbctx *dbctx,
203                 const struct skshash *hash,
204                 struct openpgp_publickey **publickey)
205 {
206         struct onak_stacked_dbctx *privctx =
207                         (struct onak_stacked_dbctx *) dbctx->priv;
208         struct onak_dbctx *backend;
209         struct ll *cur;
210         int res = 0;
211
212         for (cur = privctx->backends; cur != NULL && res == 0;
213                         cur = cur->next) {
214                 backend = (struct onak_dbctx *) cur->object;
215                 res = backend->fetch_key_skshash(backend, hash, publickey);
216         }
217
218         if (privctx->store_on_fallback && cur != privctx->backends) {
219                 store_on_fallback(privctx, *publickey, false);
220         }
221
222         return res;
223 }
224
225 /*
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.
230  */
231 #define NEED_KEYID2UID 1
232 #define NEED_GETKEYSIGS 1
233 #define NEED_GETFULLKEYID 1
234 #define NEED_UPDATEKEYS 1
235 #include "keydb.c"
236
237 static struct ll *stacked_getkeysigs(struct onak_dbctx *dbctx,
238                 uint64_t keyid, bool *revoked)
239 {
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;
244         struct ll *res;
245
246         res = backend->getkeysigs(backend, keyid, revoked);
247         if (res == NULL) {
248                 res = generic_getkeysigs(dbctx, keyid, revoked);
249         }
250
251         return res;
252 }
253
254 static struct ll *stacked_cached_getkeysigs(struct onak_dbctx *dbctx,
255                 uint64_t keyid)
256 {
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;
261         struct ll *res;
262
263         res = backend->cached_getkeysigs(backend, keyid);
264         if (res == NULL) {
265                 res = generic_cached_getkeysigs(dbctx, keyid);
266         }
267
268         return res;
269 }
270
271 static char *stacked_keyid2uid(struct onak_dbctx *dbctx,
272                         uint64_t keyid)
273 {
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;
278         char *res = NULL;
279
280         res = backend->keyid2uid(backend, keyid);
281         if (!res) {
282                 res = generic_keyid2uid(dbctx, keyid);
283         }
284
285         return res;
286 }
287
288 static uint64_t stacked_getfullkeyid(struct onak_dbctx *dbctx,
289                 uint64_t keyid)
290 {
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;
295         uint64_t res = 0;
296
297         res = backend->getfullkeyid(backend, keyid);
298         if (res == 0) {
299                 res = generic_getfullkeyid(dbctx, keyid);
300         }
301
302         return res;
303 }
304
305 static void stacked_cleanupdb(struct onak_dbctx *dbctx)
306 {
307         struct onak_stacked_dbctx *privctx =
308                         (struct onak_stacked_dbctx *) dbctx->priv;
309         struct onak_dbctx *backend;
310         struct ll *cur;
311         int res = 0;
312
313         for (cur = privctx->backends; cur != NULL && res == 0;
314                         cur = cur->next) {
315                 backend = (struct onak_dbctx *) cur->object;
316                 backend->cleanupdb(backend);
317         }
318
319         if (dbctx->priv != NULL) {
320                 free(dbctx->priv);
321                 dbctx->priv = NULL;
322         }
323
324         if (dbctx != NULL) {
325                 free(dbctx);
326         }
327 }
328
329 struct onak_dbctx *keydb_stacked_init(struct onak_db_config *dbcfg,
330                 bool readonly)
331 {
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;
337
338         if (dbcfg == NULL) {
339                 logthing(LOGTHING_CRITICAL,
340                         "No backend database configuration supplied.");
341                 return NULL;
342         }
343
344         dbctx = malloc(sizeof(struct onak_dbctx));
345
346         if (dbctx == NULL) {
347                 return NULL;
348         }
349
350         dbctx->config = dbcfg;
351         dbctx->priv = privctx = malloc(sizeof(struct onak_stacked_dbctx));
352         if (dbctx->priv == NULL) {
353                 free(dbctx);
354                 return (NULL);
355         }
356
357         /* TODO: Make configurable? */
358         privctx->store_on_fallback = true;
359         privctx->backends = NULL;
360
361         backend_name = strtok_r(dbcfg->location, ":", &saveptr);
362         while (backend_name != NULL) {
363                 backend_cfg = find_db_backend_config(config.backends,
364                                 backend_name);
365                 if (backend_cfg == NULL) {
366                         logthing(LOGTHING_CRITICAL,
367                                 "Couldn't find configuration for %s backend",
368                                 backend_name);
369                         stacked_cleanupdb(dbctx);
370                         return NULL;
371                 }
372                 logthing(LOGTHING_INFO, "Loading stacked backend: %s",
373                                 backend_cfg->name);
374
375                 backend = config.dbinit(backend_cfg, readonly);
376                 privctx->backends = lladdend(privctx->backends, backend);
377
378                 backend_name = strtok_r(NULL, ":", &saveptr);
379         }
380
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;
397         }
398
399         return dbctx;
400 }