Add key iteration functionality to keydb backends.
[onak.git] / keydb_file.c
1 /*
2  * keydb.c - Routines to store and fetch keys.
3  *
4  * Jonathan McDowell <noodles@earth.li>
5  *
6  * Copyright 2002-2004 Project Purple
7  */
8
9 #include <sys/types.h>
10 #include <sys/uio.h>
11 #include <dirent.h>
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <unistd.h>
18
19 #include "charfuncs.h"
20 #include "keydb.h"
21 #include "keyid.h"
22 #include "keystructs.h"
23 #include "ll.h"
24 #include "log.h"
25 #include "mem.h"
26 #include "onak-conf.h"
27 #include "parsekey.h"
28
29 /**
30  *      initdb - Initialize the key database.
31  *
32  *      This is just a no-op for flat file access.
33  */
34 void initdb(bool readonly)
35 {
36 }
37
38 /**
39  *      cleanupdb - De-initialize the key database.
40  *
41  *      This is just a no-op for flat file access.
42  */
43 void cleanupdb(void)
44 {
45 }
46
47 /**
48  *      starttrans - Start a transaction.
49  *
50  *      This is just a no-op for flat file access.
51  */
52 bool starttrans(void)
53 {
54         return true;
55 }
56
57 /**
58  *      endtrans - End a transaction.
59  *
60  *      This is just a no-op for flat file access.
61  */
62 void endtrans(void)
63 {
64         return;
65 }
66
67 /**
68  *      fetch_key - Given a keyid fetch the key from storage.
69  *      @keyid: The keyid to fetch.
70  *      @publickey: A pointer to a structure to return the key in.
71  *      @intrans: If we're already in a transaction.
72  *
73  *      We use the hex representation of the keyid as the filename to fetch the
74  *      key from. The key is stored in the file as a binary OpenPGP stream of
75  *      packets, so we can just use read_openpgp_stream() to read the packets
76  *      in and then parse_keys() to parse the packets into a publickey
77  *      structure.
78  */
79 int fetch_key(uint64_t keyid, struct openpgp_publickey **publickey,
80                 bool intrans)
81 {
82         struct openpgp_packet_list *packets = NULL;
83         char keyfile[1024];
84         int fd = -1;
85
86         snprintf(keyfile, 1023, "%s/0x%llX", config.db_dir,
87                         keyid & 0xFFFFFFFF);
88         fd = open(keyfile, O_RDONLY); // | O_SHLOCK);
89
90         if (fd > -1) {
91                 read_openpgp_stream(file_fetchchar, &fd, &packets, 0);
92                 parse_keys(packets, publickey);
93                 free_packet_list(packets);
94                 packets = NULL;
95                 close(fd);
96         }
97
98         return (fd > -1);
99 }
100
101 /**
102  *      store_key - Takes a key and stores it.
103  *      @publickey: A pointer to the public key to store.
104  *      @intrans: If we're already in a transaction.
105  *      @update: If true the key exists and should be updated.
106  *
107  *      Again we just use the hex representation of the keyid as the filename
108  *      to store the key to. We flatten the public key to a list of OpenPGP
109  *      packets and then use write_openpgp_stream() to write the stream out to
110  *      the file.
111  */
112 int store_key(struct openpgp_publickey *publickey, bool intrans, bool update)
113 {
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
120         snprintf(keyfile, 1023, "%s/0x%llX", config.db_dir,
121                         get_keyid(publickey) & 0xFFFFFFFF);
122         fd = open(keyfile, O_WRONLY | O_CREAT, 0664); // | O_EXLOCK);
123
124         if (fd > -1) {
125                 next = publickey -> next;
126                 publickey -> next = NULL;
127                 flatten_publickey(publickey, &packets, &list_end);
128                 publickey -> next = next;
129                 
130                 write_openpgp_stream(file_putchar, &fd, packets);
131                 close(fd);
132                 free_packet_list(packets);
133                 packets = NULL;
134         }
135
136         return (fd > -1);
137 }
138
139 /**
140  *      delete_key - Given a keyid delete the key from storage.
141  *      @keyid: The keyid to delete.
142  *      @intrans: If we're already in a transaction.
143  *
144  *      This function deletes a public key from whatever storage mechanism we
145  *      are using. Returns 0 if the key existed.
146  */
147 int delete_key(uint64_t keyid, bool intrans)
148 {
149         char keyfile[1024];
150
151         snprintf(keyfile, 1023, "%s/0x%llX", config.db_dir,
152                         keyid & 0xFFFFFFFF);
153
154         return unlink(keyfile);
155 }
156
157 /**
158  *      fetch_key_text - Trys to find the keys that contain the supplied text.
159  *      @search: The text to search for.
160  *      @publickey: A pointer to a structure to return the key in.
161  *
162  *      This function searches for the supplied text and returns the keys that
163  *      contain it.
164  *
165  *      TODO: Write for flat file access. Some sort of grep?
166  */
167 int fetch_key_text(const char *search, struct openpgp_publickey **publickey)
168 {
169         return 0;
170 }
171
172 /**
173  *      iterate_keys - call a function once for each key in the db.
174  *      @iterfunc: The function to call.
175  *      @ctx: A context pointer
176  *
177  *      Calls iterfunc once for each key in the database. ctx is passed
178  *      unaltered to iterfunc. This function is intended to aid database dumps
179  *      and statistic calculations.
180  *
181  *      Returns the number of keys we iterated over.
182  */
183 int iterate_keys(void (*iterfunc)(void *ctx, struct openpgp_publickey *key),
184                 void *ctx)
185 {
186         int                         numkeys = 0;
187         struct openpgp_packet_list *packets = NULL;
188         struct openpgp_publickey   *key = NULL;
189         DIR                        *dir;
190         char                        keyfile[1024];
191         int                         fd = -1;
192         struct dirent              *curfile = NULL;
193
194         dir = opendir(config.db_dir);
195
196         if (dir != NULL) {
197                 while ((curfile = readdir(dir)) != NULL) {
198                         if (curfile->d_name[0] == '0' &&
199                                         curfile->d_name[1] == 'x') {
200                                 snprintf(keyfile, 1023, "%s/%s",
201                                                 config.db_dir,
202                                                 curfile->d_name);
203                                 fd = open(keyfile, O_RDONLY);
204
205                                 if (fd > -1) {
206                                         read_openpgp_stream(file_fetchchar,
207                                                         &fd,
208                                                         &packets,
209                                                         0);
210                                         parse_keys(packets, &key);
211
212                                         iterfunc(ctx, key);
213
214                                         free_publickey(key);
215                                         key = NULL;
216                                         free_packet_list(packets);
217                                         packets = NULL;
218                                         close(fd);
219                                 }
220                                 numkeys++;
221                         }
222                 }
223                 
224                 closedir(dir);
225                 dir = NULL;
226         }
227
228         return numkeys;
229 }
230
231
232 /**
233  *      dumpdb - dump the key database
234  *      @filenamebase: The base filename to use for the dump.
235  *
236  *      Dumps the database into one or more files, which contain pure OpenPGP
237  *      that can be reimported into onak or gpg. filenamebase provides a base
238  *      file name for the dump; several files may be created, all of which will
239  *      begin with this string and then have a unique number and a .pgp
240  *      extension.
241  *          */
242 int dumpdb(char *filenamebase)
243 {
244         return 0;
245 }
246
247 /*
248  * Include the basic keydb routines.
249  */
250 #define NEED_KEYID2UID 1
251 #define NEED_GETKEYSIGS 1
252 #define NEED_GETFULLKEYID 1
253 #define NEED_UPDATEKEYS 1
254 #include "keydb.c"