]> the.earth.li Git - onak.git/blob - keydb/keydb_file.c
0.6.3 release
[onak.git] / keydb / keydb_file.c
1 /*
2  * keydb.c - Routines to store and fetch keys.
3  *
4  * Copyright 2002-2004 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 <sys/types.h>
20 #include <sys/uio.h>
21 #include <dirent.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <inttypes.h>
25 #include <stdbool.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30
31 #include "build-config.h"
32 #include "charfuncs.h"
33 #include "key-store.h"
34 #include "keydb.h"
35 #include "keyid.h"
36 #include "keystructs.h"
37 #include "log.h"
38 #include "mem.h"
39 #include "onak.h"
40 #include "onak-conf.h"
41 #include "parsekey.h"
42
43 /**
44  *      starttrans - Start a transaction.
45  *
46  *      This is just a no-op for flat file access.
47  */
48 static bool file_starttrans(__unused struct onak_dbctx *dbctx)
49 {
50         return true;
51 }
52
53 /**
54  *      endtrans - End a transaction.
55  *
56  *      This is just a no-op for flat file access.
57  */
58 static void file_endtrans(__unused struct onak_dbctx *dbctx)
59 {
60         return;
61 }
62
63 /**
64  *      fetch_key_id - Given a keyid fetch the key from storage.
65  *      @keyid: The keyid to fetch.
66  *      @publickey: A pointer to a structure to return the key in.
67  *      @intrans: If we're already in a transaction.
68  *
69  *      We use the hex representation of the keyid as the filename to fetch the
70  *      key from. The key is stored in the file as a binary OpenPGP stream of
71  *      packets, so we can just use read_openpgp_stream() to read the packets
72  *      in and then parse_keys() to parse the packets into a publickey
73  *      structure.
74  */
75 static int file_fetch_key_id(struct onak_dbctx *dbctx,
76                 uint64_t keyid,
77                 struct openpgp_publickey **publickey,
78                 __unused bool intrans)
79 {
80         char *db_dir = (char *) dbctx->priv;
81         struct openpgp_packet_list *packets = NULL;
82         char keyfile[1024];
83         onak_status_t res;
84
85         snprintf(keyfile, 1023, "%s/0x%" PRIX64, db_dir,
86                         keyid & 0xFFFFFFFF);
87         res = onak_read_openpgp_file(keyfile, &packets);
88
89         if (res == ONAK_E_OK) {
90                 parse_keys(packets, publickey);
91                 free_packet_list(packets);
92                 packets = NULL;
93         }
94
95         return (res == ONAK_E_OK);
96 }
97
98 /**
99  *      store_key - Takes a key and stores it.
100  *      @publickey: A pointer to the public key to store.
101  *      @intrans: If we're already in a transaction.
102  *      @update: If true the key exists and should be updated.
103  *
104  *      Again we just use the hex representation of the keyid as the filename
105  *      to store the key to. We flatten the public key to a list of OpenPGP
106  *      packets and then use write_openpgp_stream() to write the stream out to
107  *      the file.
108  */
109 static int file_store_key(struct onak_dbctx *dbctx,
110                 struct openpgp_publickey *publickey, __unused bool intrans,
111                 __unused bool update)
112 {
113         char *db_dir = (char *) dbctx->priv;
114         struct openpgp_packet_list *packets = NULL;
115         struct openpgp_packet_list *list_end = NULL;
116         struct openpgp_publickey *next = NULL;
117         char keyfile[1024];
118         int fd = -1;
119         uint64_t keyid;
120
121         if (get_keyid(publickey, &keyid) != ONAK_E_OK) {
122                 logthing(LOGTHING_ERROR, "Couldn't find key ID for key.");
123                 return 0;
124         }
125         snprintf(keyfile, 1023, "%s/0x%" PRIX64, db_dir,
126                         keyid & 0xFFFFFFFF);
127         fd = open(keyfile, O_WRONLY | O_CREAT, 0664); // | O_EXLOCK);
128
129         if (fd > -1) {
130                 next = publickey -> next;
131                 publickey -> next = NULL;
132                 flatten_publickey(publickey, &packets, &list_end);
133                 publickey -> next = next;
134                 
135                 write_openpgp_stream(file_putchar, &fd, packets);
136                 close(fd);
137                 free_packet_list(packets);
138                 packets = NULL;
139         }
140
141         return (fd > -1);
142 }
143
144 /**
145  *      delete_key - Given a keyid delete the key from storage.
146  *      @fp: The fingerprint of the key to delete.
147  *      @intrans: If we're already in a transaction.
148  *
149  *      This function deletes a public key from whatever storage mechanism we
150  *      are using. Returns 0 if the key existed.
151  */
152 static int file_delete_key(struct onak_dbctx *dbctx,
153                 struct openpgp_fingerprint *fp, __unused bool intrans)
154 {
155         char *db_dir = (char *) dbctx->priv;
156         char keyfile[1024];
157
158         snprintf(keyfile, 1023, "%s/0x%" PRIX64, db_dir,
159                         fingerprint2keyid(fp) & 0xFFFFFFFF);
160
161         return unlink(keyfile);
162 }
163
164 /**
165  *      fetch_key_text - Trys to find the keys that contain the supplied text.
166  *      @search: The text to search for.
167  *      @publickey: A pointer to a structure to return the key in.
168  *
169  *      This function searches for the supplied text and returns the keys that
170  *      contain it.
171  *
172  *      TODO: Write for flat file access. Some sort of grep?
173  */
174 static int file_fetch_key_text(__unused struct onak_dbctx *dbctx,
175                 __unused const char *search,
176                 __unused struct openpgp_publickey **publickey)
177 {
178         return 0;
179 }
180
181 /**
182  *      iterate_keys - call a function once for each key in the db.
183  *      @iterfunc: The function to call.
184  *      @ctx: A context pointer
185  *
186  *      Calls iterfunc once for each key in the database. ctx is passed
187  *      unaltered to iterfunc. This function is intended to aid database dumps
188  *      and statistic calculations.
189  *
190  *      Returns the number of keys we iterated over.
191  */
192 static int file_iterate_keys(struct onak_dbctx *dbctx,
193                 void (*iterfunc)(void *ctx, struct openpgp_publickey *key),
194                 void *ctx)
195 {
196         char *db_dir = (char *) dbctx->priv;
197         int                         numkeys = 0;
198         struct openpgp_packet_list *packets = NULL;
199         struct openpgp_publickey   *key = NULL;
200         DIR                        *dir;
201         char                        keyfile[1024];
202         struct dirent              *curfile = NULL;
203         onak_status_t               res;
204
205         dir = opendir(db_dir);
206
207         if (dir != NULL) {
208                 while ((curfile = readdir(dir)) != NULL) {
209                         if (curfile->d_name[0] == '0' &&
210                                         curfile->d_name[1] == 'x') {
211                                 snprintf(keyfile, 1023, "%s/%s",
212                                                 db_dir,
213                                                 curfile->d_name);
214                                 res = onak_read_openpgp_file(keyfile,
215                                                 &packets);
216
217                                 if (res == ONAK_E_OK) {
218                                         parse_keys(packets, &key);
219
220                                         iterfunc(ctx, key);
221
222                                         free_publickey(key);
223                                         key = NULL;
224                                         free_packet_list(packets);
225                                         packets = NULL;
226                                 }
227                                 numkeys++;
228                         }
229                 }
230                 
231                 closedir(dir);
232                 dir = NULL;
233         }
234
235         return numkeys;
236 }
237
238 /*
239  * Include the basic keydb routines.
240  */
241 #define NEED_KEYID2UID 1
242 #define NEED_GETKEYSIGS 1
243 #define NEED_UPDATEKEYS 1
244 #define NEED_GET_FP 1
245 #include "keydb.c"
246
247 /**
248  *      cleanupdb - De-initialize the key database.
249  *
250  *      This is just a no-op for flat file access.
251  */
252 static void file_cleanupdb(struct onak_dbctx *dbctx)
253 {
254         if (dbctx->priv != NULL) {
255                 free(dbctx->priv);
256                 dbctx->priv = NULL;
257         }
258
259         if (dbctx != NULL) {
260                 free(dbctx);
261         }
262 }
263
264 /**
265  *      initdb - Initialize the key database.
266  *
267  *      This is just a no-op for flat file access.
268  */
269 struct onak_dbctx *keydb_file_init(struct onak_db_config *dbcfg,
270                 __unused bool readonly)
271 {
272         struct onak_dbctx *dbctx;
273
274         dbctx = malloc(sizeof(struct onak_dbctx));
275         if (dbctx == NULL) {
276                 return NULL;
277         }
278
279         dbctx->config = dbcfg;
280         dbctx->priv = strdup(dbcfg->location);
281
282         dbctx->cleanupdb                = file_cleanupdb;
283         dbctx->starttrans               = file_starttrans;
284         dbctx->endtrans                 = file_endtrans;
285         /* Our fetch fp doesn't look at subkeys */
286         dbctx->fetch_key                = generic_fetch_key_fp;
287         dbctx->fetch_key_fp             = generic_fetch_key_fp;
288         dbctx->fetch_key_id             = file_fetch_key_id;
289         dbctx->fetch_key_text           = file_fetch_key_text;
290         dbctx->store_key                = file_store_key;
291         dbctx->update_keys              = generic_update_keys;
292         dbctx->delete_key               = file_delete_key;
293         dbctx->getkeysigs               = generic_getkeysigs;
294         dbctx->cached_getkeysigs        = generic_cached_getkeysigs;
295         dbctx->keyid2uid                = generic_keyid2uid;
296         dbctx->iterate_keys             = file_iterate_keys;
297
298         return dbctx;
299 }