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