]> git.sommitrealweird.co.uk Git - onak.git/blob - keydb_keyd.c
Make keyd background itself by default
[onak.git] / keydb_keyd.c
1 /*
2  * keydb_keyd.c - Routines to talk to keyd backend.
3  *
4  * Jonathan McDowell <noodles@earth.li>
5  *
6  * Copyright 2004 Project Purple
7  */
8
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <sys/socket.h>
15 #include <sys/types.h>
16 #include <sys/un.h>
17 #include <unistd.h>
18
19 #include "charfuncs.h"
20 #include "keyd.h"
21 #include "keydb.h"
22 #include "keyid.h"
23 #include "keystructs.h"
24 #include "log.h"
25 #include "mem.h"
26 #include "onak-conf.h"
27 #include "parsekey.h"
28
29 /**
30  *      keyd_fd - our file descriptor for the socket connection to keyd.
31  */
32 static int keyd_fd = -1;
33
34 /**
35  *      initdb - Initialize the key database.
36  *      @readonly: If we'll only be reading the DB, not writing to it.
37  *
38  *      This function should be called before any of the other functions in
39  *      this file are called in order to allow the DB to be initialized ready
40  *      for access.
41  */
42 static void keyd_initdb(bool readonly)
43 {
44         struct sockaddr_un sock;
45         int                cmd = KEYD_CMD_UNKNOWN;
46         int                reply = KEYD_REPLY_UNKNOWN_CMD;
47         ssize_t            count;
48
49         keyd_fd = socket(PF_UNIX, SOCK_STREAM, 0);
50         if (keyd_fd < 0) {
51                 logthing(LOGTHING_CRITICAL,
52                                 "Couldn't open socket: %s (%d)",
53                                 strerror(errno),
54                                 errno);
55                 exit(EXIT_FAILURE);
56         }
57
58         sock.sun_family = AF_UNIX;
59         snprintf(sock.sun_path, sizeof(sock.sun_path) - 1, "%s/%s",
60                         config.db_dir,
61                         KEYD_SOCKET);
62         if (connect(keyd_fd, (struct sockaddr *) &sock, sizeof(sock)) < 0) {
63                 logthing(LOGTHING_CRITICAL,
64                                 "Couldn't connect to socket %s: %s (%d)",
65                                 sock.sun_path,
66                                 strerror(errno),
67                                 errno);
68                 exit(EXIT_FAILURE);
69         }
70
71         cmd = KEYD_CMD_VERSION;
72         if (write(keyd_fd, &cmd, sizeof(cmd)) != sizeof(cmd)) {
73                 logthing(LOGTHING_CRITICAL,
74                                 "Couldn't write version cmd: %s (%d)",
75                                 strerror(errno),
76                                 errno);
77         } else {
78                 count = read(keyd_fd, &reply, sizeof(reply));
79                 if (count == sizeof(reply)) {
80                         if (reply == KEYD_REPLY_OK) {
81                                 count = read(keyd_fd, &reply, sizeof(reply));
82                                 logthing(LOGTHING_DEBUG,
83                                                 "keyd protocol version %d",
84                                                 reply);
85                                 if (reply != keyd_version) {
86                                         logthing(LOGTHING_CRITICAL,
87                                                 "Error! keyd protocol version "
88                                                 "mismatch. (us = %d, it = %d)",
89                                                 keyd_version, reply);
90                                 }
91                         }
92                 }
93         }
94
95         return;
96 }
97
98 /**
99  *      cleanupdb - De-initialize the key database.
100  *
101  *      This function should be called upon program exit to allow the DB to
102  *      cleanup after itself.
103  */
104 static void keyd_cleanupdb(void)
105 {
106         int cmd = KEYD_CMD_CLOSE;
107
108         if (write(keyd_fd, &cmd, sizeof(cmd)) != sizeof(cmd)) {
109                 logthing(LOGTHING_CRITICAL,
110                                 "Couldn't send close cmd: %s (%d)",
111                                 strerror(errno),
112                                 errno);
113         }
114
115         if (shutdown(keyd_fd, SHUT_RDWR) < 0) {
116                 logthing(LOGTHING_NOTICE, "Error shutting down socket: %d",
117                                 errno);
118         }
119         if (close(keyd_fd) < 0) {
120                 logthing(LOGTHING_NOTICE, "Error closing down socket: %d",
121                                 errno);
122         }
123         keyd_fd = -1;
124
125         return;
126 }
127
128
129 /**
130  *      starttrans - Start a transaction.
131  *
132  *      Start a transaction. Intended to be used if we're about to perform many
133  *      operations on the database to help speed it all up, or if we want
134  *      something to only succeed if all relevant operations are successful.
135  */
136 static bool keyd_starttrans(void)
137 {
138         return true;
139 }
140
141 /**
142  *      endtrans - End a transaction.
143  *
144  *      Ends a transaction.
145  */
146 static void keyd_endtrans(void)
147 {
148         return;
149 }
150
151 /**
152  *      fetch_key - Given a keyid fetch the key from storage.
153  *      @keyid: The keyid to fetch.
154  *      @publickey: A pointer to a structure to return the key in.
155  *      @intrans: If we're already in a transaction.
156  *
157  *      This function returns a public key from whatever storage mechanism we
158  *      are using.
159  *
160  *      TODO: What about keyid collisions? Should we use fingerprint instead?
161  */
162 static int keyd_fetch_key(uint64_t keyid, struct openpgp_publickey **publickey,
163                 bool intrans)
164 {
165         struct buffer_ctx           keybuf;
166         struct openpgp_packet_list *packets = NULL;
167         int                         cmd = KEYD_CMD_GET;
168         ssize_t                     bytes = 0;
169         ssize_t                     count = 0;
170
171         write(keyd_fd, &cmd, sizeof(cmd));
172         read(keyd_fd, &cmd, sizeof(cmd));
173         if (cmd == KEYD_REPLY_OK) {
174                 write(keyd_fd, &keyid, sizeof(keyid));
175                 keybuf.offset = 0;
176                 read(keyd_fd, &keybuf.size, sizeof(keybuf.size));
177                 if (keybuf.size > 0) {
178                         keybuf.buffer = malloc(keybuf.size);
179                         bytes = count = 0;
180                         logthing(LOGTHING_TRACE,
181                                         "Getting %d bytes of key data.",
182                                         keybuf.size);
183                         while (bytes >= 0 && count < keybuf.size) {
184                                 bytes = read(keyd_fd, &keybuf.buffer[count],
185                                                 keybuf.size - count);
186                                 logthing(LOGTHING_TRACE,
187                                                 "Read %d bytes.", bytes);
188                                 count += bytes;
189                         }
190                         read_openpgp_stream(buffer_fetchchar, &keybuf,
191                                         &packets, 0);
192                         parse_keys(packets, publickey);
193                         free_packet_list(packets);
194                         packets = NULL;
195                         free(keybuf.buffer);
196                         keybuf.buffer = NULL;
197                         keybuf.size = 0;
198                 }
199         }
200         
201         return (count > 0) ? 1 : 0;
202 }
203
204 /**
205 *       delete_key - Given a keyid delete the key from storage.
206 *       @keyid: The keyid to delete.
207 *       @intrans: If we're already in a transaction.
208 *
209 *       This function deletes a public key from whatever storage mechanism we
210 *       are using. Returns 0 if the key existed.
211 */
212 static int keyd_delete_key(uint64_t keyid, bool intrans)
213 {
214         int cmd = KEYD_CMD_DELETE;
215
216         write(keyd_fd, &cmd, sizeof(cmd));
217         read(keyd_fd, &cmd, sizeof(cmd));
218         if (cmd == KEYD_REPLY_OK) {
219                 write(keyd_fd, &keyid, sizeof(keyid));
220         }
221
222         return 0;
223 }
224
225 /**
226  *      store_key - Takes a key and stores it.
227  *      @publickey: A pointer to the public key to store.
228  *      @intrans: If we're already in a transaction.
229  *      @update: If true the key exists and should be updated.
230  *
231  *      This function stores a public key in whatever storage mechanism we are
232  *      using. intrans indicates if we're already in a transaction so don't
233  *      need to start one. update indicates if the key already exists and is
234  *      just being updated.
235  *
236  *      TODO: Do we store multiple keys of the same id? Or only one and replace
237  *      it?
238  */
239 static int keyd_store_key(struct openpgp_publickey *publickey, bool intrans,
240                 bool update)
241 {
242         struct buffer_ctx           keybuf;
243         struct openpgp_packet_list *packets = NULL;
244         struct openpgp_packet_list *list_end = NULL;
245         struct openpgp_publickey   *next = NULL;
246         int                         cmd = KEYD_CMD_STORE;
247         uint64_t                    keyid;
248
249         keyid = get_keyid(publickey);
250         
251         if (update) {
252                 keyd_delete_key(keyid, false);
253         }
254
255         write(keyd_fd, &cmd, sizeof(cmd));
256         read(keyd_fd, &cmd, sizeof(cmd));
257         if (cmd == KEYD_REPLY_OK) {
258                 keybuf.offset = 0;
259                 keybuf.size = 8192;
260                 keybuf.buffer = malloc(keybuf.size);
261
262                 next = publickey->next;
263                 publickey->next = NULL;
264                 flatten_publickey(publickey,
265                                 &packets,
266                                 &list_end);
267                 publickey->next = next;
268
269                 write_openpgp_stream(buffer_putchar, &keybuf, packets);
270                 logthing(LOGTHING_TRACE, "Sending %d bytes.", keybuf.offset);
271                 write(keyd_fd, &keybuf.offset, sizeof(keybuf.offset));
272                 write(keyd_fd, keybuf.buffer, keybuf.offset);
273
274                 free_packet_list(packets);
275                 packets = list_end = NULL;
276                 free(keybuf.buffer);
277                 keybuf.buffer = NULL;
278                 keybuf.size = keybuf.offset = 0;
279         }
280         
281         return 0;
282 }
283
284 /**
285  *      fetch_key_text - Trys to find the keys that contain the supplied text.
286  *      @search: The text to search for.
287  *      @publickey: A pointer to a structure to return the key in.
288  *
289  *      This function searches for the supplied text and returns the keys that
290  *      contain it.
291  */
292 static int keyd_fetch_key_text(const char *search,
293                 struct openpgp_publickey **publickey)
294 {
295         struct buffer_ctx           keybuf;
296         struct openpgp_packet_list *packets = NULL;
297         int                         cmd = KEYD_CMD_GETTEXT;
298         ssize_t                     bytes = 0;
299         ssize_t                     count = 0;
300
301         write(keyd_fd, &cmd, sizeof(cmd));
302         read(keyd_fd, &cmd, sizeof(cmd));
303         if (cmd == KEYD_REPLY_OK) {
304                 bytes = strlen(search);
305                 write(keyd_fd, &bytes, sizeof(bytes));
306                 write(keyd_fd, search, bytes);
307                 keybuf.offset = 0;
308                 read(keyd_fd, &keybuf.size, sizeof(keybuf.size));
309                 if (keybuf.size > 0) {
310                         keybuf.buffer = malloc(keybuf.size);
311                         bytes = count = 0;
312                         logthing(LOGTHING_TRACE,
313                                         "Getting %d bytes of key data.",
314                                         keybuf.size);
315                         while (bytes >= 0 && count < keybuf.size) {
316                                 bytes = read(keyd_fd, &keybuf.buffer[count],
317                                                 keybuf.size - count);
318                                 logthing(LOGTHING_TRACE,
319                                                 "Read %d bytes.", bytes);
320                                 count += bytes;
321                         }
322                         read_openpgp_stream(buffer_fetchchar, &keybuf,
323                                         &packets, 0);
324                         parse_keys(packets, publickey);
325                         free_packet_list(packets);
326                         packets = NULL;
327                         free(keybuf.buffer);
328                         keybuf.buffer = NULL;
329                         keybuf.size = 0;
330                 }
331         }
332         
333         return (count > 0) ? 1 : 0;
334
335         return 0;
336 }
337
338 /**
339  *      getfullkeyid - Maps a 32bit key id to a 64bit one.
340  *      @keyid: The 32bit keyid.
341  *
342  *      This function maps a 32bit key id to the full 64bit one. It returns the
343  *      full keyid. If the key isn't found a keyid of 0 is returned.
344  */
345 static uint64_t keyd_getfullkeyid(uint64_t keyid)
346 {
347         int cmd = KEYD_CMD_GETFULLKEYID;
348
349         write(keyd_fd, &cmd, sizeof(cmd));
350         read(keyd_fd, &cmd, sizeof(cmd));
351         if (cmd == KEYD_REPLY_OK) {
352                 write(keyd_fd, &keyid, sizeof(keyid));
353                 read(keyd_fd, &keyid, sizeof(keyid));
354         }
355
356         return keyid;
357 }
358
359 /**
360  *      iterate_keys - call a function once for each key in the db.
361  *      @iterfunc: The function to call.
362  *      @ctx: A context pointer
363  *
364  *      Calls iterfunc once for each key in the database. ctx is passed
365  *      unaltered to iterfunc. This function is intended to aid database dumps
366  *      and statistic calculations.
367  *
368  *      Returns the number of keys we iterated over.
369  */
370 static int keyd_iterate_keys(void (*iterfunc)(void *ctx,
371                 struct openpgp_publickey *key), void *ctx)
372 {
373         struct buffer_ctx           keybuf;
374         struct openpgp_packet_list *packets = NULL;
375         struct openpgp_publickey   *key = NULL;
376         int                         cmd = KEYD_CMD_KEYITER;
377         ssize_t                     bytes = 0;
378         ssize_t                     count = 0;
379         int                         numkeys = 0;
380
381         write(keyd_fd, &cmd, sizeof(cmd));
382         read(keyd_fd, &cmd, sizeof(cmd));
383         if (cmd == KEYD_REPLY_OK) {
384                 keybuf.offset = 0;
385                 read(keyd_fd, &keybuf.size, sizeof(keybuf.size));
386                 while (keybuf.size > 0) {
387                         keybuf.buffer = malloc(keybuf.size);
388                         bytes = count = 0;
389                         logthing(LOGTHING_TRACE,
390                                         "Getting %d bytes of key data.",
391                                         keybuf.size);
392                         while (bytes >= 0 && count < keybuf.size) {
393                                 bytes = read(keyd_fd, &keybuf.buffer[count],
394                                                 keybuf.size - count);
395                                 logthing(LOGTHING_TRACE,
396                                                 "Read %d bytes.", bytes);
397                                 count += bytes;
398                         }
399                         read_openpgp_stream(buffer_fetchchar, &keybuf,
400                                         &packets, 0);
401                         parse_keys(packets, &key);
402
403                         if (iterfunc != NULL && key != NULL) {
404                                 iterfunc(ctx, key);
405                         }
406
407                         free_publickey(key);
408                         key = NULL;
409                         free_packet_list(packets);
410                         packets = NULL;
411                         free(keybuf.buffer);
412                         keybuf.buffer = NULL;
413                         keybuf.size = keybuf.offset = 0;
414
415                         numkeys++;
416
417                         read(keyd_fd, &keybuf.size, sizeof(keybuf.size));
418                 }
419         }
420         
421         return numkeys;
422 }
423
424 #define NEED_KEYID2UID 1
425 #define NEED_GETKEYSIGS 1
426 #define NEED_UPDATEKEYS 1
427 #include "keydb.c"
428
429 struct dbfuncs keydb_keyd_funcs = {
430         .initdb                 = keyd_initdb,
431         .cleanupdb              = keyd_cleanupdb,
432         .starttrans             = keyd_starttrans,
433         .endtrans               = keyd_endtrans,
434         .fetch_key              = keyd_fetch_key,
435         .fetch_key_text         = keyd_fetch_key_text,
436         .store_key              = keyd_store_key,
437         .update_keys            = generic_update_keys,
438         .delete_key             = keyd_delete_key,
439         .getkeysigs             = generic_getkeysigs,
440         .cached_getkeysigs      = generic_cached_getkeysigs,
441         .keyid2uid              = generic_keyid2uid,
442         .getfullkeyid           = keyd_getfullkeyid,
443         .iterate_keys           = keyd_iterate_keys,
444 };