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