]> git.sommitrealweird.co.uk Git - onak.git/blob - keydb_keyd.c
ceedd87a84de1337c36524d4a8012fd4464557b8
[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         uint32_t           cmd = KEYD_CMD_UNKNOWN;
46         uint32_t           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) && reply == KEYD_REPLY_OK) {
80                         count = read(keyd_fd, &reply, sizeof(reply));
81                         if (count != sizeof(reply) || reply != sizeof(reply)) {
82                                 logthing(LOGTHING_CRITICAL,
83                                         "Error! Unexpected keyd version "
84                                         "length: %d != %d",
85                                         reply, sizeof(reply));
86                                 exit(EXIT_FAILURE);
87                         }
88
89                         count = read(keyd_fd, &reply, sizeof(reply));
90                         logthing(LOGTHING_DEBUG,
91                                         "keyd protocol version %d",
92                                         reply);
93                         if (reply != keyd_version) {
94                                 logthing(LOGTHING_CRITICAL,
95                                         "Error! keyd protocol version "
96                                         "mismatch. (us = %d, it = %d)",
97                                                 keyd_version, reply);
98                         }
99                 }
100         }
101
102         return;
103 }
104
105 /**
106  *      cleanupdb - De-initialize the key database.
107  *
108  *      This function should be called upon program exit to allow the DB to
109  *      cleanup after itself.
110  */
111 static void keyd_cleanupdb(void)
112 {
113         uint32_t cmd = KEYD_CMD_CLOSE;
114
115         if (write(keyd_fd, &cmd, sizeof(cmd)) != sizeof(cmd)) {
116                 logthing(LOGTHING_CRITICAL,
117                                 "Couldn't send close cmd: %s (%d)",
118                                 strerror(errno),
119                                 errno);
120         }
121         
122         if (read(keyd_fd, &cmd, sizeof(cmd)) != sizeof(cmd)) {
123                 logthing(LOGTHING_CRITICAL,
124                         "Couldn't read close cmd reply: %s (%d)",
125                         strerror(errno),
126                         errno);
127         } else if (cmd != KEYD_REPLY_OK) {
128                 logthing(LOGTHING_CRITICAL,
129                         "Got bad reply to KEYD_CMD_CLOSE: %d", cmd);
130         }
131
132         if (shutdown(keyd_fd, SHUT_RDWR) < 0) {
133                 logthing(LOGTHING_NOTICE, "Error shutting down socket: %d",
134                                 errno);
135         }
136         if (close(keyd_fd) < 0) {
137                 logthing(LOGTHING_NOTICE, "Error closing down socket: %d",
138                                 errno);
139         }
140         keyd_fd = -1;
141
142         return;
143 }
144
145
146 /**
147  *      starttrans - Start a transaction.
148  *
149  *      Start a transaction. Intended to be used if we're about to perform many
150  *      operations on the database to help speed it all up, or if we want
151  *      something to only succeed if all relevant operations are successful.
152  */
153 static bool keyd_starttrans(void)
154 {
155         return true;
156 }
157
158 /**
159  *      endtrans - End a transaction.
160  *
161  *      Ends a transaction.
162  */
163 static void keyd_endtrans(void)
164 {
165         return;
166 }
167
168 /**
169  *      fetch_key - Given a keyid fetch the key from storage.
170  *      @keyid: The keyid to fetch.
171  *      @publickey: A pointer to a structure to return the key in.
172  *      @intrans: If we're already in a transaction.
173  *
174  *      This function returns a public key from whatever storage mechanism we
175  *      are using.
176  *
177  *      TODO: What about keyid collisions? Should we use fingerprint instead?
178  */
179 static int keyd_fetch_key(uint64_t keyid, struct openpgp_publickey **publickey,
180                 bool intrans)
181 {
182         struct buffer_ctx           keybuf;
183         struct openpgp_packet_list *packets = NULL;
184         uint32_t                    cmd = KEYD_CMD_GET;
185         ssize_t                     bytes = 0;
186         ssize_t                     count = 0;
187
188         write(keyd_fd, &cmd, sizeof(cmd));
189         read(keyd_fd, &cmd, sizeof(cmd));
190         if (cmd == KEYD_REPLY_OK) {
191                 write(keyd_fd, &keyid, sizeof(keyid));
192                 keybuf.offset = 0;
193                 read(keyd_fd, &keybuf.size, sizeof(keybuf.size));
194                 if (keybuf.size > 0) {
195                         keybuf.buffer = malloc(keybuf.size);
196                         bytes = count = 0;
197                         logthing(LOGTHING_TRACE,
198                                         "Getting %d bytes of key data.",
199                                         keybuf.size);
200                         while (bytes >= 0 && count < keybuf.size) {
201                                 bytes = read(keyd_fd, &keybuf.buffer[count],
202                                                 keybuf.size - count);
203                                 logthing(LOGTHING_TRACE,
204                                                 "Read %d bytes.", bytes);
205                                 count += bytes;
206                         }
207                         read_openpgp_stream(buffer_fetchchar, &keybuf,
208                                         &packets, 0);
209                         parse_keys(packets, publickey);
210                         free_packet_list(packets);
211                         packets = NULL;
212                         free(keybuf.buffer);
213                         keybuf.buffer = NULL;
214                         keybuf.size = 0;
215                 }
216         }
217         
218         return (count > 0) ? 1 : 0;
219 }
220
221 /**
222 *       delete_key - Given a keyid delete the key from storage.
223 *       @keyid: The keyid to delete.
224 *       @intrans: If we're already in a transaction.
225 *
226 *       This function deletes a public key from whatever storage mechanism we
227 *       are using. Returns 0 if the key existed.
228 */
229 static int keyd_delete_key(uint64_t keyid, bool intrans)
230 {
231         uint32_t cmd = KEYD_CMD_DELETE;
232
233         write(keyd_fd, &cmd, sizeof(cmd));
234         read(keyd_fd, &cmd, sizeof(cmd));
235         if (cmd == KEYD_REPLY_OK) {
236                 write(keyd_fd, &keyid, sizeof(keyid));
237         }
238
239         return 0;
240 }
241
242 /**
243  *      store_key - Takes a key and stores it.
244  *      @publickey: A pointer to the public key to store.
245  *      @intrans: If we're already in a transaction.
246  *      @update: If true the key exists and should be updated.
247  *
248  *      This function stores a public key in whatever storage mechanism we are
249  *      using. intrans indicates if we're already in a transaction so don't
250  *      need to start one. update indicates if the key already exists and is
251  *      just being updated.
252  *
253  *      TODO: Do we store multiple keys of the same id? Or only one and replace
254  *      it?
255  */
256 static int keyd_store_key(struct openpgp_publickey *publickey, bool intrans,
257                 bool update)
258 {
259         struct buffer_ctx           keybuf;
260         struct openpgp_packet_list *packets = NULL;
261         struct openpgp_packet_list *list_end = NULL;
262         struct openpgp_publickey   *next = NULL;
263         uint32_t                    cmd = KEYD_CMD_STORE;
264         uint64_t                    keyid;
265
266         keyid = get_keyid(publickey);
267         
268         if (update) {
269                 keyd_delete_key(keyid, false);
270         }
271
272         write(keyd_fd, &cmd, sizeof(cmd));
273         read(keyd_fd, &cmd, sizeof(cmd));
274         if (cmd == KEYD_REPLY_OK) {
275                 keybuf.offset = 0;
276                 keybuf.size = 8192;
277                 keybuf.buffer = malloc(keybuf.size);
278
279                 next = publickey->next;
280                 publickey->next = NULL;
281                 flatten_publickey(publickey,
282                                 &packets,
283                                 &list_end);
284                 publickey->next = next;
285
286                 write_openpgp_stream(buffer_putchar, &keybuf, packets);
287                 logthing(LOGTHING_TRACE, "Sending %d bytes.", keybuf.offset);
288                 write(keyd_fd, &keybuf.offset, sizeof(keybuf.offset));
289                 write(keyd_fd, keybuf.buffer, keybuf.offset);
290
291                 free_packet_list(packets);
292                 packets = list_end = NULL;
293                 free(keybuf.buffer);
294                 keybuf.buffer = NULL;
295                 keybuf.size = keybuf.offset = 0;
296         }
297         
298         return 0;
299 }
300
301 /**
302  *      fetch_key_text - Trys to find the keys that contain the supplied text.
303  *      @search: The text to search for.
304  *      @publickey: A pointer to a structure to return the key in.
305  *
306  *      This function searches for the supplied text and returns the keys that
307  *      contain it.
308  */
309 static int keyd_fetch_key_text(const char *search,
310                 struct openpgp_publickey **publickey)
311 {
312         struct buffer_ctx           keybuf;
313         struct openpgp_packet_list *packets = NULL;
314         uint32_t                    cmd = KEYD_CMD_GETTEXT;
315         ssize_t                     bytes = 0;
316         ssize_t                     count = 0;
317
318         write(keyd_fd, &cmd, sizeof(cmd));
319         read(keyd_fd, &cmd, sizeof(cmd));
320         if (cmd == KEYD_REPLY_OK) {
321                 bytes = strlen(search);
322                 write(keyd_fd, &bytes, sizeof(bytes));
323                 write(keyd_fd, search, bytes);
324                 keybuf.offset = 0;
325                 read(keyd_fd, &keybuf.size, sizeof(keybuf.size));
326                 if (keybuf.size > 0) {
327                         keybuf.buffer = malloc(keybuf.size);
328                         bytes = count = 0;
329                         logthing(LOGTHING_TRACE,
330                                         "Getting %d bytes of key data.",
331                                         keybuf.size);
332                         while (bytes >= 0 && count < keybuf.size) {
333                                 bytes = read(keyd_fd, &keybuf.buffer[count],
334                                                 keybuf.size - count);
335                                 logthing(LOGTHING_TRACE,
336                                                 "Read %d bytes.", bytes);
337                                 count += bytes;
338                         }
339                         read_openpgp_stream(buffer_fetchchar, &keybuf,
340                                         &packets, 0);
341                         parse_keys(packets, publickey);
342                         free_packet_list(packets);
343                         packets = NULL;
344                         free(keybuf.buffer);
345                         keybuf.buffer = NULL;
346                         keybuf.size = 0;
347                 }
348         }
349         
350         return (count > 0) ? 1 : 0;
351
352         return 0;
353 }
354
355 static int keyd_fetch_key_skshash(const struct skshash *hash,
356                 struct openpgp_publickey **publickey)
357 {
358         struct buffer_ctx           keybuf;
359         struct openpgp_packet_list *packets = NULL;
360         uint32_t                    cmd = KEYD_CMD_GETSKSHASH;
361         ssize_t                     bytes = 0;
362         ssize_t                     count = 0;
363
364         write(keyd_fd, &cmd, sizeof(cmd));
365         read(keyd_fd, &cmd, sizeof(cmd));
366         if (cmd == KEYD_REPLY_OK) {
367                 write(keyd_fd, hash->hash, sizeof(hash->hash));
368                 keybuf.offset = 0;
369                 read(keyd_fd, &keybuf.size, sizeof(keybuf.size));
370                 if (keybuf.size > 0) {
371                         keybuf.buffer = malloc(keybuf.size);
372                         bytes = count = 0;
373                         logthing(LOGTHING_TRACE,
374                                         "Getting %d bytes of key data.",
375                                         keybuf.size);
376                         while (bytes >= 0 && count < keybuf.size) {
377                                 bytes = read(keyd_fd, &keybuf.buffer[count],
378                                                 keybuf.size - count);
379                                 logthing(LOGTHING_TRACE,
380                                                 "Read %d bytes.", bytes);
381                                 count += bytes;
382                         }
383                         read_openpgp_stream(buffer_fetchchar, &keybuf,
384                                         &packets, 0);
385                         parse_keys(packets, publickey);
386                         free_packet_list(packets);
387                         packets = NULL;
388                         free(keybuf.buffer);
389                         keybuf.buffer = NULL;
390                         keybuf.size = 0;
391                 }
392         }
393         
394         return (count > 0) ? 1 : 0;
395 }
396
397
398 /**
399  *      getfullkeyid - Maps a 32bit key id to a 64bit one.
400  *      @keyid: The 32bit keyid.
401  *
402  *      This function maps a 32bit key id to the full 64bit one. It returns the
403  *      full keyid. If the key isn't found a keyid of 0 is returned.
404  */
405 static uint64_t keyd_getfullkeyid(uint64_t keyid)
406 {
407         uint32_t cmd = KEYD_CMD_GETFULLKEYID;
408
409         write(keyd_fd, &cmd, sizeof(cmd));
410         read(keyd_fd, &cmd, sizeof(cmd));
411         if (cmd == KEYD_REPLY_OK) {
412                 write(keyd_fd, &keyid, sizeof(keyid));
413                 read(keyd_fd, &cmd, sizeof(cmd));
414                 if (cmd != sizeof(keyid)) {
415                         return 0;
416                 }
417                 read(keyd_fd, &keyid, sizeof(keyid));
418         }
419
420         return keyid;
421 }
422
423 /**
424  *      iterate_keys - call a function once for each key in the db.
425  *      @iterfunc: The function to call.
426  *      @ctx: A context pointer
427  *
428  *      Calls iterfunc once for each key in the database. ctx is passed
429  *      unaltered to iterfunc. This function is intended to aid database dumps
430  *      and statistic calculations.
431  *
432  *      Returns the number of keys we iterated over.
433  */
434 static int keyd_iterate_keys(void (*iterfunc)(void *ctx,
435                 struct openpgp_publickey *key), void *ctx)
436 {
437         struct buffer_ctx           keybuf;
438         struct openpgp_packet_list *packets = NULL;
439         struct openpgp_publickey   *key = NULL;
440         uint32_t                    cmd = KEYD_CMD_KEYITER;
441         ssize_t                     bytes = 0;
442         ssize_t                     count = 0;
443         int                         numkeys = 0;
444
445         write(keyd_fd, &cmd, sizeof(cmd));
446         read(keyd_fd, &cmd, sizeof(cmd));
447         if (cmd == KEYD_REPLY_OK) {
448                 keybuf.offset = 0;
449                 read(keyd_fd, &keybuf.size, sizeof(keybuf.size));
450                 while (keybuf.size > 0) {
451                         keybuf.buffer = malloc(keybuf.size);
452                         bytes = count = 0;
453                         logthing(LOGTHING_TRACE,
454                                         "Getting %d bytes of key data.",
455                                         keybuf.size);
456                         while (bytes >= 0 && count < keybuf.size) {
457                                 bytes = read(keyd_fd, &keybuf.buffer[count],
458                                                 keybuf.size - count);
459                                 logthing(LOGTHING_TRACE,
460                                                 "Read %d bytes.", bytes);
461                                 count += bytes;
462                         }
463                         read_openpgp_stream(buffer_fetchchar, &keybuf,
464                                         &packets, 0);
465                         parse_keys(packets, &key);
466
467                         if (iterfunc != NULL && key != NULL) {
468                                 iterfunc(ctx, key);
469                         }
470
471                         free_publickey(key);
472                         key = NULL;
473                         free_packet_list(packets);
474                         packets = NULL;
475                         free(keybuf.buffer);
476                         keybuf.buffer = NULL;
477                         keybuf.size = keybuf.offset = 0;
478
479                         numkeys++;
480
481                         read(keyd_fd, &keybuf.size, sizeof(keybuf.size));
482                 }
483         }
484         
485         return numkeys;
486 }
487
488 #define NEED_KEYID2UID 1
489 #define NEED_GETKEYSIGS 1
490 #define NEED_UPDATEKEYS 1
491 #include "keydb.c"
492
493 struct dbfuncs keydb_keyd_funcs = {
494         .initdb                 = keyd_initdb,
495         .cleanupdb              = keyd_cleanupdb,
496         .starttrans             = keyd_starttrans,
497         .endtrans               = keyd_endtrans,
498         .fetch_key              = keyd_fetch_key,
499         .fetch_key_text         = keyd_fetch_key_text,
500         .fetch_key_skshash      = keyd_fetch_key_skshash,
501         .store_key              = keyd_store_key,
502         .update_keys            = generic_update_keys,
503         .delete_key             = keyd_delete_key,
504         .getkeysigs             = generic_getkeysigs,
505         .cached_getkeysigs      = generic_cached_getkeysigs,
506         .keyid2uid              = generic_keyid2uid,
507         .getfullkeyid           = keyd_getfullkeyid,
508         .iterate_keys           = keyd_iterate_keys,
509 };