]> the.earth.li Git - onak.git/blob - keydb/keydb_keyd.c
e8f9961b79a6d2f9364ec53e6dd42abe70953ec5
[onak.git] / keydb / keydb_keyd.c
1 /*
2  * keydb_keyd.c - Routines to talk to keyd backend.
3  *
4  * Copyright 2002-2004,2011 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 <errno.h>
20 #include <fcntl.h>
21 #include <stdbool.h>
22 #include <stdint.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/socket.h>
27 #include <sys/types.h>
28 #include <sys/un.h>
29 #include <unistd.h>
30
31 #include "charfuncs.h"
32 #include "keyd.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  *      Start a transaction. Intended to be used if we're about to perform many
46  *      operations on the database to help speed it all up, or if we want
47  *      something to only succeed if all relevant operations are successful.
48  */
49 static bool keyd_starttrans(struct onak_dbctx *dbctx)
50 {
51         return true;
52 }
53
54 /**
55  *      endtrans - End a transaction.
56  *
57  *      Ends a transaction.
58  */
59 static void keyd_endtrans(struct onak_dbctx *dbctx)
60 {
61         return;
62 }
63
64 static bool keyd_send_cmd(int fd, enum keyd_ops _cmd)
65 {
66         uint32_t cmd = _cmd;
67         ssize_t bytes;
68
69         bytes = write(fd, &cmd, sizeof(cmd));
70         if (bytes != sizeof(cmd)) {
71                 return false;
72         }
73
74         bytes = read(fd, &cmd, sizeof(cmd));
75         if (bytes != sizeof(cmd)) {
76                 return false;
77         }
78
79         if (cmd != KEYD_REPLY_OK) {
80                 return false;
81         }
82
83         return true;
84 }
85
86 /**
87  *      fetch_key - Given a keyid fetch the key from storage.
88  *      @keyid: The keyid to fetch.
89  *      @publickey: A pointer to a structure to return the key in.
90  *      @intrans: If we're already in a transaction.
91  *
92  *      This function returns a public key from whatever storage mechanism we
93  *      are using.
94  *
95  *      TODO: What about keyid collisions? Should we use fingerprint instead?
96  */
97 static int keyd_fetch_key_id(struct onak_dbctx *dbctx,
98                 uint64_t keyid,
99                 struct openpgp_publickey **publickey,
100                 bool intrans)
101 {
102         int keyd_fd = (intptr_t) dbctx->priv;
103         struct buffer_ctx           keybuf;
104         struct openpgp_packet_list *packets = NULL;
105         ssize_t                     bytes = 0;
106         ssize_t                     count = 0;
107
108         if (keyd_send_cmd(keyd_fd, KEYD_CMD_GET_ID)) {
109                 write(keyd_fd, &keyid, sizeof(keyid));
110                 keybuf.offset = 0;
111                 read(keyd_fd, &keybuf.size, sizeof(keybuf.size));
112                 if (keybuf.size > 0) {
113                         keybuf.buffer = malloc(keybuf.size);
114                         bytes = count = 0;
115                         logthing(LOGTHING_TRACE,
116                                         "Getting %d bytes of key data.",
117                                         keybuf.size);
118                         while (bytes >= 0 && count < keybuf.size) {
119                                 bytes = read(keyd_fd, &keybuf.buffer[count],
120                                                 keybuf.size - count);
121                                 logthing(LOGTHING_TRACE,
122                                                 "Read %d bytes.", bytes);
123                                 count += bytes;
124                         }
125                         read_openpgp_stream(buffer_fetchchar, &keybuf,
126                                         &packets, 0);
127                         parse_keys(packets, publickey);
128                         free_packet_list(packets);
129                         packets = NULL;
130                         free(keybuf.buffer);
131                         keybuf.buffer = NULL;
132                         keybuf.size = 0;
133                 }
134         }
135
136         return (count > 0) ? 1 : 0;
137 }
138
139 static int keyd_fetch_key_fp(struct onak_dbctx *dbctx,
140                 struct openpgp_fingerprint *fingerprint,
141                 struct openpgp_publickey **publickey,
142                 bool intrans)
143 {
144         int keyd_fd = (intptr_t) dbctx->priv;
145         struct buffer_ctx           keybuf;
146         struct openpgp_packet_list *packets = NULL;
147         ssize_t                     bytes = 0;
148         ssize_t                     count = 0;
149         uint8_t                     size;
150
151         if (fingerprint->length > MAX_FINGERPRINT_LEN) {
152                 return 0;
153         }
154
155         if (keyd_send_cmd(keyd_fd, KEYD_CMD_GET_FP)) {
156                 size = fingerprint->length;
157                 write(keyd_fd, &size, sizeof(size));
158                 write(keyd_fd, fingerprint->fp, size);
159                 keybuf.offset = 0;
160                 read(keyd_fd, &keybuf.size, sizeof(keybuf.size));
161                 if (keybuf.size > 0) {
162                         keybuf.buffer = malloc(keybuf.size);
163                         bytes = count = 0;
164                         logthing(LOGTHING_TRACE,
165                                         "Getting %d bytes of key data.",
166                                         keybuf.size);
167                         while (bytes >= 0 && count < keybuf.size) {
168                                 bytes = read(keyd_fd, &keybuf.buffer[count],
169                                                 keybuf.size - count);
170                                 logthing(LOGTHING_TRACE,
171                                                 "Read %d bytes.", bytes);
172                                 count += bytes;
173                         }
174                         read_openpgp_stream(buffer_fetchchar, &keybuf,
175                                         &packets, 0);
176                         parse_keys(packets, publickey);
177                         free_packet_list(packets);
178                         packets = NULL;
179                         free(keybuf.buffer);
180                         keybuf.buffer = NULL;
181                         keybuf.size = 0;
182                 }
183         }
184
185         return (count > 0) ? 1 : 0;
186 }
187
188 /**
189 *       delete_key - Given a keyid delete the key from storage.
190  *      @fp: The fingerprint of the key to delete.
191 *       @intrans: If we're already in a transaction.
192 *
193 *       This function deletes a public key from whatever storage mechanism we
194 *       are using. Returns 0 if the key existed.
195 */
196 static int keyd_delete_key(struct onak_dbctx *dbctx,
197                 struct openpgp_fingerprint *fp, bool intrans)
198 {
199         int keyd_fd = (intptr_t) dbctx->priv;
200
201         if (keyd_send_cmd(keyd_fd, KEYD_CMD_DELETE)) {
202                 write(keyd_fd, fp, sizeof(*fp));
203         }
204
205         return 0;
206 }
207
208 /**
209  *      store_key - Takes a key and stores it.
210  *      @publickey: A pointer to the public key to store.
211  *      @intrans: If we're already in a transaction.
212  *      @update: If true the key exists and should be updated.
213  *
214  *      This function stores a public key in whatever storage mechanism we are
215  *      using. intrans indicates if we're already in a transaction so don't
216  *      need to start one. update indicates if the key already exists and is
217  *      just being updated.
218  *
219  *      TODO: Do we store multiple keys of the same id? Or only one and replace
220  *      it?
221  */
222 static int keyd_store_key(struct onak_dbctx *dbctx,
223                 struct openpgp_publickey *publickey, bool intrans,
224                 bool update)
225 {
226         int keyd_fd = (intptr_t) dbctx->priv;
227         struct buffer_ctx           keybuf;
228         struct openpgp_packet_list *packets = NULL;
229         struct openpgp_packet_list *list_end = NULL;
230         struct openpgp_publickey   *next = NULL;
231         uint64_t                    keyid;
232         enum keyd_ops               cmd = KEYD_CMD_STORE;
233
234         if (get_keyid(publickey, &keyid) != ONAK_E_OK) {
235                 logthing(LOGTHING_ERROR, "Couldn't find key ID for key.");
236                 return 0;
237         }
238
239         if (update) {
240                 cmd = KEYD_CMD_UPDATE;
241         }
242
243         if (keyd_send_cmd(keyd_fd, cmd)) {
244                 keybuf.offset = 0;
245                 keybuf.size = 8192;
246                 keybuf.buffer = malloc(keybuf.size);
247
248                 next = publickey->next;
249                 publickey->next = NULL;
250                 flatten_publickey(publickey,
251                                 &packets,
252                                 &list_end);
253                 publickey->next = next;
254
255                 write_openpgp_stream(buffer_putchar, &keybuf, packets);
256                 logthing(LOGTHING_TRACE, "Sending %d bytes.", keybuf.offset);
257                 write(keyd_fd, &keybuf.offset, sizeof(keybuf.offset));
258                 write(keyd_fd, keybuf.buffer, keybuf.offset);
259
260                 free_packet_list(packets);
261                 packets = list_end = NULL;
262                 free(keybuf.buffer);
263                 keybuf.buffer = NULL;
264                 keybuf.size = keybuf.offset = 0;
265         }
266
267         return 0;
268 }
269
270 /**
271  *      fetch_key_text - Trys to find the keys that contain the supplied text.
272  *      @search: The text to search for.
273  *      @publickey: A pointer to a structure to return the key in.
274  *
275  *      This function searches for the supplied text and returns the keys that
276  *      contain it.
277  */
278 static int keyd_fetch_key_text(struct onak_dbctx *dbctx,
279                 const char *search,
280                 struct openpgp_publickey **publickey)
281 {
282         int keyd_fd = (intptr_t) dbctx->priv;
283         struct buffer_ctx           keybuf;
284         struct openpgp_packet_list *packets = NULL;
285         ssize_t                     bytes = 0;
286         ssize_t                     count = 0;
287
288         if (keyd_send_cmd(keyd_fd, KEYD_CMD_GET_TEXT)) {
289                 bytes = strlen(search);
290                 write(keyd_fd, &bytes, sizeof(bytes));
291                 write(keyd_fd, search, bytes);
292                 keybuf.offset = 0;
293                 read(keyd_fd, &keybuf.size, sizeof(keybuf.size));
294                 if (keybuf.size > 0) {
295                         keybuf.buffer = malloc(keybuf.size);
296                         bytes = count = 0;
297                         logthing(LOGTHING_TRACE,
298                                         "Getting %d bytes of key data.",
299                                         keybuf.size);
300                         while (bytes >= 0 && count < keybuf.size) {
301                                 bytes = read(keyd_fd, &keybuf.buffer[count],
302                                                 keybuf.size - count);
303                                 logthing(LOGTHING_TRACE,
304                                                 "Read %d bytes.", bytes);
305                                 count += bytes;
306                         }
307                         read_openpgp_stream(buffer_fetchchar, &keybuf,
308                                         &packets, 0);
309                         parse_keys(packets, publickey);
310                         free_packet_list(packets);
311                         packets = NULL;
312                         free(keybuf.buffer);
313                         keybuf.buffer = NULL;
314                         keybuf.size = 0;
315                 }
316         }
317
318         return (count > 0) ? 1 : 0;
319
320         return 0;
321 }
322
323 static int keyd_fetch_key_skshash(struct onak_dbctx *dbctx,
324                 const struct skshash *hash,
325                 struct openpgp_publickey **publickey)
326 {
327         int keyd_fd = (intptr_t) dbctx->priv;
328         struct buffer_ctx           keybuf;
329         struct openpgp_packet_list *packets = NULL;
330         ssize_t                     bytes = 0;
331         ssize_t                     count = 0;
332
333         if (keyd_send_cmd(keyd_fd, KEYD_CMD_GET_SKSHASH)) {
334                 write(keyd_fd, hash->hash, sizeof(hash->hash));
335                 keybuf.offset = 0;
336                 read(keyd_fd, &keybuf.size, sizeof(keybuf.size));
337                 if (keybuf.size > 0) {
338                         keybuf.buffer = malloc(keybuf.size);
339                         bytes = count = 0;
340                         logthing(LOGTHING_TRACE,
341                                         "Getting %d bytes of key data.",
342                                         keybuf.size);
343                         while (bytes >= 0 && count < keybuf.size) {
344                                 bytes = read(keyd_fd, &keybuf.buffer[count],
345                                                 keybuf.size - count);
346                                 logthing(LOGTHING_TRACE,
347                                                 "Read %d bytes.", bytes);
348                                 count += bytes;
349                         }
350                         read_openpgp_stream(buffer_fetchchar, &keybuf,
351                                         &packets, 0);
352                         parse_keys(packets, publickey);
353                         free_packet_list(packets);
354                         packets = NULL;
355                         free(keybuf.buffer);
356                         keybuf.buffer = NULL;
357                         keybuf.size = 0;
358                 }
359         }
360
361         return (count > 0) ? 1 : 0;
362 }
363
364 /**
365  *      iterate_keys - call a function once for each key in the db.
366  *      @iterfunc: The function to call.
367  *      @ctx: A context pointer
368  *
369  *      Calls iterfunc once for each key in the database. ctx is passed
370  *      unaltered to iterfunc. This function is intended to aid database dumps
371  *      and statistic calculations.
372  *
373  *      Returns the number of keys we iterated over.
374  */
375 static int keyd_iterate_keys(struct onak_dbctx *dbctx,
376                 void (*iterfunc)(void *ctx,
377                 struct openpgp_publickey *key), void *ctx)
378 {
379         int keyd_fd = (intptr_t) dbctx->priv;
380         struct buffer_ctx           keybuf;
381         struct openpgp_packet_list *packets = NULL;
382         struct openpgp_publickey   *key = NULL;
383         ssize_t                     bytes = 0;
384         ssize_t                     count = 0;
385         int                         numkeys = 0;
386
387         if (keyd_send_cmd(keyd_fd, KEYD_CMD_KEYITER)) {
388                 keybuf.offset = 0;
389                 read(keyd_fd, &keybuf.size, sizeof(keybuf.size));
390                 while (keybuf.size > 0) {
391                         keybuf.buffer = malloc(keybuf.size);
392                         bytes = count = 0;
393                         logthing(LOGTHING_TRACE,
394                                         "Getting %d bytes of key data.",
395                                         keybuf.size);
396                         while (bytes >= 0 && count < keybuf.size) {
397                                 bytes = read(keyd_fd, &keybuf.buffer[count],
398                                                 keybuf.size - count);
399                                 logthing(LOGTHING_TRACE,
400                                                 "Read %d bytes.", bytes);
401                                 count += bytes;
402                         }
403                         read_openpgp_stream(buffer_fetchchar, &keybuf,
404                                         &packets, 0);
405                         parse_keys(packets, &key);
406
407                         if (iterfunc != NULL && key != NULL) {
408                                 iterfunc(ctx, key);
409                         }
410
411                         free_publickey(key);
412                         key = NULL;
413                         free_packet_list(packets);
414                         packets = NULL;
415                         free(keybuf.buffer);
416                         keybuf.buffer = NULL;
417                         keybuf.size = keybuf.offset = 0;
418
419                         numkeys++;
420
421                         read(keyd_fd, &keybuf.size, sizeof(keybuf.size));
422                 }
423         }
424
425         return numkeys;
426 }
427
428 #define NEED_KEYID2UID 1
429 #define NEED_GETKEYSIGS 1
430 #define NEED_UPDATEKEYS 1
431 #include "keydb.c"
432
433 /**
434  *      cleanupdb - De-initialize the key database.
435  *
436  *      This function should be called upon program exit to allow the DB to
437  *      cleanup after itself.
438  */
439 static void keyd_cleanupdb(struct onak_dbctx *dbctx)
440 {
441         int keyd_fd = (intptr_t) dbctx->priv;
442         uint32_t cmd = KEYD_CMD_CLOSE;
443
444         if (write(keyd_fd, &cmd, sizeof(cmd)) != sizeof(cmd)) {
445                 logthing(LOGTHING_CRITICAL,
446                                 "Couldn't send close cmd: %s (%d)",
447                                 strerror(errno),
448                                 errno);
449         }
450
451         if (read(keyd_fd, &cmd, sizeof(cmd)) != sizeof(cmd)) {
452                 logthing(LOGTHING_CRITICAL,
453                         "Couldn't read close cmd reply: %s (%d)",
454                         strerror(errno),
455                         errno);
456         } else if (cmd != KEYD_REPLY_OK) {
457                 logthing(LOGTHING_CRITICAL,
458                         "Got bad reply to KEYD_CMD_CLOSE: %d", cmd);
459         }
460
461         if (shutdown(keyd_fd, SHUT_RDWR) < 0) {
462                 logthing(LOGTHING_NOTICE, "Error shutting down socket: %d",
463                                 errno);
464         }
465         if (close(keyd_fd) < 0) {
466                 logthing(LOGTHING_NOTICE, "Error closing down socket: %d",
467                                 errno);
468         }
469
470         free(dbctx);
471
472         return;
473 }
474
475 /**
476  *      initdb - Initialize the key database.
477  *      @readonly: If we'll only be reading the DB, not writing to it.
478  *
479  *      This function should be called before any of the other functions in
480  *      this file are called in order to allow the DB to be initialized ready
481  *      for access.
482  */
483 struct onak_dbctx *keydb_keyd_init(struct onak_db_config *dbcfg, bool readonly)
484 {
485         struct sockaddr_un sock;
486         uint32_t           cmd = KEYD_CMD_UNKNOWN;
487         uint32_t           reply = KEYD_REPLY_UNKNOWN_CMD;
488         ssize_t            count;
489         int keyd_fd;
490         struct onak_dbctx *dbctx;
491
492         dbctx = malloc(sizeof(*dbctx));
493         if (dbctx == NULL) {
494                 return NULL;
495         }
496         dbctx->config = dbcfg;
497
498         keyd_fd = socket(PF_UNIX, SOCK_STREAM, 0);
499         if (keyd_fd < 0) {
500                 logthing(LOGTHING_CRITICAL,
501                                 "Couldn't open socket: %s (%d)",
502                                 strerror(errno),
503                                 errno);
504                 exit(EXIT_FAILURE);
505         }
506
507         sock.sun_family = AF_UNIX;
508         snprintf(sock.sun_path, sizeof(sock.sun_path) - 1, "%s/%s",
509                         config.sock_dir,
510                         KEYD_SOCKET);
511         if (connect(keyd_fd, (struct sockaddr *) &sock, sizeof(sock)) < 0) {
512                 logthing(LOGTHING_CRITICAL,
513                                 "Couldn't connect to socket %s: %s (%d)",
514                                 sock.sun_path,
515                                 strerror(errno),
516                                 errno);
517                 exit(EXIT_FAILURE);
518         }
519
520         cmd = KEYD_CMD_VERSION;
521         if (write(keyd_fd, &cmd, sizeof(cmd)) != sizeof(cmd)) {
522                 logthing(LOGTHING_CRITICAL,
523                                 "Couldn't write version cmd: %s (%d)",
524                                 strerror(errno),
525                                 errno);
526         } else {
527                 count = read(keyd_fd, &reply, sizeof(reply));
528                 if (count == sizeof(reply) && reply == KEYD_REPLY_OK) {
529                         count = read(keyd_fd, &reply, sizeof(reply));
530                         if (count != sizeof(reply) || reply != sizeof(reply)) {
531                                 logthing(LOGTHING_CRITICAL,
532                                         "Error! Unexpected keyd version "
533                                         "length: %d != %d",
534                                         reply, sizeof(reply));
535                                 exit(EXIT_FAILURE);
536                         }
537
538                         count = read(keyd_fd, &reply, sizeof(reply));
539                         if (count != sizeof(reply)) {
540                                 logthing(LOGTHING_CRITICAL,
541                                         "Error! Unexpected keyd version "
542                                         "length: %d != %d",
543                                         count, sizeof(reply));
544                                 exit(EXIT_FAILURE);
545                         }
546                         logthing(LOGTHING_DEBUG,
547                                         "keyd protocol version %d",
548                                         reply);
549                         if (reply != keyd_version) {
550                                 logthing(LOGTHING_CRITICAL,
551                                         "Error! keyd protocol version "
552                                         "mismatch. (us = %d, it = %d)",
553                                                 keyd_version, reply);
554                         }
555                 }
556         }
557
558         dbctx->priv                     = (void *) (intptr_t) keyd_fd;
559         dbctx->cleanupdb                = keyd_cleanupdb;
560         dbctx->starttrans               = keyd_starttrans;
561         dbctx->endtrans                 = keyd_endtrans;
562         dbctx->fetch_key_id             = keyd_fetch_key_id;
563         dbctx->fetch_key_fp             = keyd_fetch_key_fp;
564         dbctx->fetch_key_text           = keyd_fetch_key_text;
565         dbctx->fetch_key_skshash        = keyd_fetch_key_skshash;
566         dbctx->store_key                = keyd_store_key;
567         dbctx->update_keys              = generic_update_keys;
568         dbctx->delete_key               = keyd_delete_key;
569         dbctx->getkeysigs               = generic_getkeysigs;
570         dbctx->cached_getkeysigs        = generic_cached_getkeysigs;
571         dbctx->keyid2uid                = generic_keyid2uid;
572         dbctx->iterate_keys             = keyd_iterate_keys;
573
574         return dbctx;
575 }