2 * keyd.c - key retrieval daemon
4 * Copyright 2004,2011 Jonathan McDowell <noodles@earth.li>
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.
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
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 51
17 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27 #include <sys/select.h>
28 #include <sys/socket.h>
29 #include <sys/types.h>
34 #include "charfuncs.h"
39 #include "keystructs.h"
42 #include "onak-conf.h"
46 /* Maximum number of clients we're prepared to accept at once */
47 #define MAX_CLIENTS 16
49 static struct keyd_stats *stats;
58 logthing(LOGTHING_CRITICAL,
59 "Failed to fork into background: %d (%s)",
64 logthing(LOGTHING_INFO, "Backgrounded as pid %d.", pid);
70 freopen("/dev/null", "r", stdin);
71 freopen("/dev/null", "w", stdout);
72 freopen("/dev/null", "w", stderr);
77 void iteratefunc(void *ctx, struct openpgp_publickey *key)
79 struct openpgp_packet_list *packets = NULL;
80 struct openpgp_packet_list *list_end = NULL;
81 struct buffer_ctx storebuf;
83 int *fd = (int *) ctx;
89 storebuf.buffer = malloc(8192);
91 get_keyid(key, &keyid);
92 logthing(LOGTHING_TRACE,
93 "Iterating over 0x%016" PRIX64 ".",
96 flatten_publickey(key,
99 write_openpgp_stream(buffer_putchar,
102 logthing(LOGTHING_TRACE,
105 ret = write(*fd, &storebuf.offset,
106 sizeof(storebuf.offset));
108 write(*fd, storebuf.buffer,
112 free(storebuf.buffer);
113 storebuf.buffer = NULL;
114 storebuf.size = storebuf.offset = 0;
115 free_packet_list(packets);
116 packets = list_end = NULL;
122 int sock_init(const char *sockname)
124 struct sockaddr_un sock;
128 fd = socket(PF_UNIX, SOCK_STREAM, 0);
130 ret = fcntl(fd, F_SETFD, FD_CLOEXEC);
134 sock.sun_family = AF_UNIX;
135 strncpy(sock.sun_path, sockname, sizeof(sock.sun_path) - 1);
137 ret = bind(fd, (struct sockaddr *) &sock, sizeof(sock));
149 uint32_t cmd = KEYD_CMD_UNKNOWN;
155 struct openpgp_publickey *key = NULL;
156 struct openpgp_packet_list *packets = NULL;
157 struct openpgp_packet_list *list_end = NULL;
158 struct buffer_ctx storebuf;
162 * Get the command from the client.
164 bytes = read(fd, &cmd, sizeof(cmd));
166 logthing(LOGTHING_DEBUG, "Read %d bytes, command: %d", bytes, cmd);
168 if (bytes != sizeof(cmd)) {
173 if (cmd < KEYD_CMD_LAST) {
174 stats->command_stats[cmd]++;
176 stats->command_stats[KEYD_CMD_UNKNOWN]++;
179 case KEYD_CMD_VERSION:
181 write(fd, &cmd, sizeof(cmd));
182 cmd = sizeof(keyd_version);
183 write(fd, &cmd, sizeof(cmd));
184 write(fd, &keyd_version, sizeof(keyd_version));
188 write(fd, &cmd, sizeof(cmd));
189 bytes = read(fd, &keyid, sizeof(keyid));
190 if (bytes != sizeof(keyid)) {
195 logthing(LOGTHING_INFO,
196 "Fetching 0x%" PRIX64
200 fetch_key(keyid, &key, false));
202 storebuf.size = 8192;
203 storebuf.buffer = malloc(8192);
205 flatten_publickey(key,
208 write_openpgp_stream(buffer_putchar,
211 logthing(LOGTHING_TRACE,
214 write(fd, &storebuf.offset,
215 sizeof(storebuf.offset));
216 write(fd, storebuf.buffer,
219 free(storebuf.buffer);
220 storebuf.buffer = NULL;
221 storebuf.size = storebuf.offset = 0;
222 free_packet_list(packets);
223 packets = list_end = NULL;
227 write(fd, &storebuf.offset,
228 sizeof(storebuf.offset));
232 case KEYD_CMD_GETTEXT:
234 write(fd, &cmd, sizeof(cmd));
235 bytes = read(fd, &count, sizeof(count));
236 if (bytes != sizeof(count)) {
241 search = malloc(count+1);
242 read(fd, search, count);
244 logthing(LOGTHING_INFO,
245 "Fetching %s, result: %d",
248 fetch_key_text(search, &key));
250 storebuf.size = 8192;
251 storebuf.buffer = malloc(8192);
253 flatten_publickey(key,
256 write_openpgp_stream(buffer_putchar,
259 logthing(LOGTHING_TRACE,
262 write(fd, &storebuf.offset,
263 sizeof(storebuf.offset));
264 write(fd, storebuf.buffer,
267 free(storebuf.buffer);
268 storebuf.buffer = NULL;
269 storebuf.size = storebuf.offset = 0;
270 free_packet_list(packets);
271 packets = list_end = NULL;
275 write(fd, &storebuf.offset,
276 sizeof(storebuf.offset));
282 write(fd, &cmd, sizeof(cmd));
284 bytes = read(fd, &storebuf.size,
285 sizeof(storebuf.size));
286 logthing(LOGTHING_TRACE, "Reading %d bytes.",
288 if (bytes != sizeof(storebuf.size)) {
291 if (ret == 0 && storebuf.size > 0) {
292 storebuf.buffer = malloc(storebuf.size);
294 while (bytes >= 0 && count < storebuf.size) {
296 &storebuf.buffer[count],
297 storebuf.size - count);
298 logthing(LOGTHING_TRACE,
303 read_openpgp_stream(buffer_fetchchar,
307 parse_keys(packets, &key);
308 config.dbbackend->store_key(key, false, false);
309 free_packet_list(packets);
313 free(storebuf.buffer);
314 storebuf.buffer = NULL;
315 storebuf.size = storebuf.offset = 0;
318 case KEYD_CMD_DELETE:
320 write(fd, &cmd, sizeof(cmd));
321 bytes = read(fd, &keyid, sizeof(keyid));
322 if (bytes != sizeof(keyid)) {
326 logthing(LOGTHING_INFO,
327 "Deleting 0x%" PRIX64
330 config.dbbackend->delete_key(
334 case KEYD_CMD_GETFULLKEYID:
336 write(fd, &cmd, sizeof(cmd));
337 bytes = read(fd, &keyid, sizeof(keyid));
338 if (bytes != sizeof(keyid)) {
342 keyid = config.dbbackend->getfullkeyid(keyid);
344 write(fd, &cmd, sizeof(cmd));
345 write(fd, &keyid, sizeof(keyid));
348 case KEYD_CMD_KEYITER:
350 write(fd, &cmd, sizeof(cmd));
351 config.dbbackend->iterate_keys(iteratefunc,
354 write(fd, &bytes, sizeof(bytes));
358 write(fd, &cmd, sizeof(cmd));
363 write(fd, &cmd, sizeof(cmd));
364 logthing(LOGTHING_NOTICE,
365 "Exiting due to quit request.");
371 write(fd, &cmd, sizeof(cmd));
372 cmd = sizeof(*stats);
373 write(fd, &cmd, sizeof(cmd));
377 case KEYD_CMD_GETSKSHASH:
379 write(fd, &cmd, sizeof(cmd));
380 bytes = read(fd, hash.hash, sizeof(hash.hash));
381 if (bytes != sizeof(hash.hash)) {
386 logthing(LOGTHING_INFO,
390 fetch_key_skshash(&hash,
393 storebuf.size = 8192;
394 storebuf.buffer = malloc(8192);
396 flatten_publickey(key,
399 write_openpgp_stream(buffer_putchar,
402 logthing(LOGTHING_TRACE,
405 write(fd, &storebuf.offset,
406 sizeof(storebuf.offset));
407 write(fd, storebuf.buffer,
410 free(storebuf.buffer);
411 storebuf.buffer = NULL;
412 storebuf.size = storebuf.offset = 0;
413 free_packet_list(packets);
414 packets = list_end = NULL;
418 write(fd, &storebuf.offset,
419 sizeof(storebuf.offset));
425 logthing(LOGTHING_ERROR, "Got unknown command: %d",
427 cmd = KEYD_REPLY_UNKNOWN_CMD;
428 write(fd, &cmd, sizeof(cmd));
435 int sock_close(int fd)
437 shutdown(fd, SHUT_RDWR);
441 int sock_accept(int fd)
443 struct sockaddr_un sock;
448 socklen = sizeof(sock);
449 srv = accept(fd, (struct sockaddr *) &sock, &socklen);
451 ret = fcntl(srv, F_SETFD, FD_CLOEXEC);
461 static void usage(void)
463 puts("keyd " ONAK_VERSION " - backend key serving daemon for the "
464 "onak PGP keyserver.\n");
466 puts("\tkeyd [options]\n");
467 puts("\tOptions:\n:");
468 puts("-c <file> - use <file> as the config file");
469 puts("-f - run in the foreground");
470 puts("-h - show this help text");
474 int main(int argc, char *argv[])
476 int fd = -1, maxfd, i, clients[MAX_CLIENTS];
479 char *configfile = NULL;
480 bool foreground = false;
483 while ((optchar = getopt(argc, argv, "c:fh")) != -1 ) {
486 configfile = strdup(optarg);
498 readconfig(configfile);
501 initlogthing("keyd", config.logfile);
502 config.use_keyd = false;
509 signal(SIGPIPE, SIG_IGN);
512 stats = calloc(1, sizeof(*stats));
514 logthing(LOGTHING_ERROR,
515 "Couldn't allocate memory for stats structure.");
518 stats->started = time(NULL);
520 snprintf(sockname, 1023, "%s/%s", config.db_dir, KEYD_SOCKET);
521 fd = sock_init(sockname);
527 memset(clients, -1, sizeof (clients));
529 config.dbbackend->initdb(false);
531 logthing(LOGTHING_NOTICE, "Accepting connections.");
532 while (!cleanup() && select(maxfd + 1, &rfds, NULL, NULL, NULL) != -1) {
534 * Deal with existing clients first; if we're at our
535 * connection limit then processing them might free
536 * things up and let us accept the next client below.
538 for (i = 0; i < MAX_CLIENTS; i++) {
539 if (clients[i] != -1 &&
540 FD_ISSET(clients[i], &rfds)) {
541 logthing(LOGTHING_DEBUG,
542 "Handling connection for client %d.", i);
543 if (sock_do(clients[i])) {
544 sock_close(clients[i]);
546 logthing(LOGTHING_DEBUG,
547 "Closed connection for client %d.", i);
552 * Check if we have a new incoming connection to accept.
554 if (FD_ISSET(fd, &rfds)) {
555 for (i = 0; i < MAX_CLIENTS; i++) {
556 if (clients[i] == -1) {
560 if (i < MAX_CLIENTS) {
561 logthing(LOGTHING_INFO,
562 "Accepted connection %d.", i);
563 clients[i] = sock_accept(fd);
569 for (i = 0; i < MAX_CLIENTS; i++) {
570 if (clients[i] != -1) {
571 FD_SET(clients[i], &rfds);
572 maxfd = (maxfd > clients[i]) ?
577 config.dbbackend->cleanupdb();
587 return(EXIT_SUCCESS);