Update Debian Vcs-* fields to point to git repository
[onak.git] / keyd.c
1 /*
2  * keyd.c - key retrieval daemon
3  *
4  * Copyright 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, write to the Free Software Foundation, Inc., 51
17  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <getopt.h>
23 #include <signal.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/select.h>
28 #include <sys/socket.h>
29 #include <sys/types.h>
30 #include <sys/un.h>
31 #include <time.h>
32 #include <unistd.h>
33
34 #include "charfuncs.h"
35 #include "cleanup.h"
36 #include "keyd.h"
37 #include "keydb.h"
38 #include "keyid.h"
39 #include "keystructs.h"
40 #include "log.h"
41 #include "mem.h"
42 #include "onak-conf.h"
43 #include "parsekey.h"
44 #include "version.h"
45
46 static struct keyd_stats *stats;
47
48 void daemonize(void)
49 {
50         pid_t pid;
51
52         pid = fork();
53
54         if (pid < 0) {
55                 logthing(LOGTHING_CRITICAL,
56                         "Failed to fork into background: %d (%s)",
57                         errno,
58                         strerror(errno));
59                 exit(EXIT_FAILURE);
60         } else if (pid > 0) {
61                 logthing(LOGTHING_INFO, "Backgrounded as pid %d.", pid);
62                 exit(EXIT_SUCCESS);
63         }
64
65         pid = setsid();
66
67         freopen("/dev/null", "r", stdin);
68         freopen("/dev/null", "w", stdout);
69         freopen("/dev/null", "w", stderr);
70
71         return;
72 }
73
74 void iteratefunc(void *ctx, struct openpgp_publickey *key)
75 {
76         struct openpgp_packet_list *packets = NULL;
77         struct openpgp_packet_list *list_end = NULL;
78         struct buffer_ctx           storebuf;
79         int                         ret = 0;
80         int                         *fd = (int *) ctx;
81         uint64_t                    keyid;
82
83         if (key != NULL) {
84                 storebuf.offset = 0;
85                 storebuf.size = 8192;
86                 storebuf.buffer = malloc(8192);
87
88                 get_keyid(key, &keyid);
89                 logthing(LOGTHING_TRACE,
90                                 "Iterating over 0x%016" PRIX64 ".",
91                                 keyid);
92
93                 flatten_publickey(key,
94                                 &packets,
95                                 &list_end);
96                 write_openpgp_stream(buffer_putchar,
97                                 &storebuf,
98                                 packets);
99                 logthing(LOGTHING_TRACE,
100                                 "Sending %d bytes.",
101                                 storebuf.offset);
102                 ret = write(*fd, &storebuf.offset,
103                         sizeof(storebuf.offset));
104                 if (ret != 0) {
105                         write(*fd, storebuf.buffer,
106                                 storebuf.offset);
107                 }
108
109                 free(storebuf.buffer);
110                 storebuf.buffer = NULL;
111                 storebuf.size = storebuf.offset = 0;
112                 free_packet_list(packets);
113                 packets = list_end = NULL;
114         }
115
116         return;
117 }
118
119 int sock_init(const char *sockname)
120 {
121         struct sockaddr_un sock;
122         int                fd = -1;
123         int                ret = -1;
124
125         fd = socket(PF_UNIX, SOCK_STREAM, 0);
126         if (fd != -1) {
127                 ret = fcntl(fd, F_SETFD, 1);
128         }
129
130         if (ret != -1) {
131                 sock.sun_family = AF_UNIX;
132                 strncpy(sock.sun_path, sockname, sizeof(sock.sun_path) - 1);
133                 unlink(sockname);
134                 ret = bind(fd, (struct sockaddr *) &sock, sizeof(sock));
135         }
136
137         if (ret != -1) {
138                 ret = listen(fd, 5);
139         }
140         
141         return fd;
142 }
143
144 int sock_do(int fd)
145 {
146         uint32_t cmd = KEYD_CMD_UNKNOWN;
147         ssize_t  bytes = 0;
148         ssize_t  count = 0;
149         int      ret = 0;
150         uint64_t keyid = 0;
151         char     *search = NULL;
152         struct openpgp_publickey *key = NULL;
153         struct openpgp_packet_list *packets = NULL;
154         struct openpgp_packet_list *list_end = NULL;
155         struct buffer_ctx storebuf;
156         struct skshash hash;
157
158         /*
159          * Get the command from the client.
160          */
161         bytes = read(fd, &cmd, sizeof(cmd));
162
163         logthing(LOGTHING_DEBUG, "Read %d bytes, command: %d", bytes, cmd);
164
165         if (bytes != sizeof(cmd)) {
166                 ret = 1;
167         }
168         
169         if (ret == 0) {
170                 if (cmd < KEYD_CMD_LAST) {
171                         stats->command_stats[cmd]++;
172                 } else {
173                         stats->command_stats[KEYD_CMD_UNKNOWN]++;
174                 }
175                 switch (cmd) {
176                 case KEYD_CMD_VERSION:
177                         cmd = KEYD_REPLY_OK;
178                         write(fd, &cmd, sizeof(cmd));
179                         cmd = sizeof(keyd_version);
180                         write(fd, &cmd, sizeof(cmd));
181                         write(fd, &keyd_version, sizeof(keyd_version));
182                         break;
183                 case KEYD_CMD_GET:
184                         cmd = KEYD_REPLY_OK;
185                         write(fd, &cmd, sizeof(cmd));
186                         bytes = read(fd, &keyid, sizeof(keyid));
187                         if (bytes != sizeof(keyid)) {
188                                 ret = 1;
189                         }
190                         storebuf.offset = 0;
191                         if (ret == 0) {
192                                 logthing(LOGTHING_INFO,
193                                                 "Fetching 0x%" PRIX64
194                                                 ", result: %d",
195                                                 keyid,
196                                                 config.dbbackend->
197                                                 fetch_key(keyid, &key, false));
198                                 if (key != NULL) {
199                                         storebuf.size = 8192;
200                                         storebuf.buffer = malloc(8192);
201
202                                         flatten_publickey(key,
203                                                         &packets,
204                                                         &list_end);
205                                         write_openpgp_stream(buffer_putchar,
206                                                         &storebuf,
207                                                         packets);
208                                         logthing(LOGTHING_TRACE,
209                                                         "Sending %d bytes.",
210                                                         storebuf.offset);
211                                         write(fd, &storebuf.offset,
212                                                 sizeof(storebuf.offset));
213                                         write(fd, storebuf.buffer,
214                                                 storebuf.offset);
215
216                                         free(storebuf.buffer);
217                                         storebuf.buffer = NULL;
218                                         storebuf.size = storebuf.offset = 0;
219                                         free_packet_list(packets);
220                                         packets = list_end = NULL;
221                                         free_publickey(key);
222                                         key = NULL;
223                                 } else {
224                                         write(fd, &storebuf.offset,
225                                                 sizeof(storebuf.offset));
226                                 }
227                         }
228                         break;
229                 case KEYD_CMD_GETTEXT:
230                         cmd = KEYD_REPLY_OK;
231                         write(fd, &cmd, sizeof(cmd));
232                         bytes = read(fd, &count, sizeof(count));
233                         if (bytes != sizeof(count)) {
234                                 ret = 1;
235                         }
236                         storebuf.offset = 0;
237                         if (ret == 0) {
238                                 search = malloc(count+1);
239                                 read(fd, search, count);
240                                 search[count] = 0;
241                                 logthing(LOGTHING_INFO,
242                                                 "Fetching %s, result: %d",
243                                                 search,
244                                                 config.dbbackend->
245                                                 fetch_key_text(search, &key));
246                                 if (key != NULL) {
247                                         storebuf.size = 8192;
248                                         storebuf.buffer = malloc(8192);
249
250                                         flatten_publickey(key,
251                                                         &packets,
252                                                         &list_end);
253                                         write_openpgp_stream(buffer_putchar,
254                                                         &storebuf,
255                                                         packets);
256                                         logthing(LOGTHING_TRACE,
257                                                         "Sending %d bytes.",
258                                                         storebuf.offset);
259                                         write(fd, &storebuf.offset,
260                                                 sizeof(storebuf.offset));
261                                         write(fd, storebuf.buffer,
262                                                 storebuf.offset);
263
264                                         free(storebuf.buffer);
265                                         storebuf.buffer = NULL;
266                                         storebuf.size = storebuf.offset = 0;
267                                         free_packet_list(packets);
268                                         packets = list_end = NULL;
269                                         free_publickey(key);
270                                         key = NULL;
271                                 } else {
272                                         write(fd, &storebuf.offset,
273                                                 sizeof(storebuf.offset));
274                                 }
275                         }
276                         break;
277                 case KEYD_CMD_STORE:
278                         cmd = KEYD_REPLY_OK;
279                         write(fd, &cmd, sizeof(cmd));
280                         storebuf.offset = 0;
281                         bytes = read(fd, &storebuf.size,
282                                         sizeof(storebuf.size));
283                         logthing(LOGTHING_TRACE, "Reading %d bytes.",
284                                         storebuf.size);
285                         if (bytes != sizeof(storebuf.size)) {
286                                 ret = 1;
287                         }
288                         if (ret == 0 && storebuf.size > 0) {
289                                 storebuf.buffer = malloc(storebuf.size);
290                                 bytes = count = 0;
291                                 while (bytes >= 0 && count < storebuf.size) {
292                                         bytes = read(fd,
293                                                 &storebuf.buffer[count],
294                                                 storebuf.size - count);
295                                         logthing(LOGTHING_TRACE,
296                                                         "Read %d bytes.",
297                                                         bytes);
298                                         count += bytes;
299                                 }
300                                 read_openpgp_stream(buffer_fetchchar,
301                                                 &storebuf,
302                                                 &packets,
303                                                 0);
304                                 parse_keys(packets, &key);
305                                 config.dbbackend->store_key(key, false, false);
306                                 free_packet_list(packets);
307                                 packets = NULL;
308                                 free_publickey(key);
309                                 key = NULL;
310                                 free(storebuf.buffer);
311                                 storebuf.buffer = NULL;
312                                 storebuf.size = storebuf.offset = 0;
313                         }
314                         break;
315                 case KEYD_CMD_DELETE:
316                         cmd = KEYD_REPLY_OK;
317                         write(fd, &cmd, sizeof(cmd));
318                         bytes = read(fd, &keyid, sizeof(keyid));
319                         if (bytes != sizeof(keyid)) {
320                                 ret = 1;
321                         }
322                         if (ret == 0) {
323                                 logthing(LOGTHING_INFO,
324                                                 "Deleting 0x%" PRIX64
325                                                 ", result: %d",
326                                                 keyid,
327                                                 config.dbbackend->delete_key(
328                                                         keyid, false));
329                         }
330                         break;
331                 case KEYD_CMD_GETFULLKEYID:
332                         cmd = KEYD_REPLY_OK;
333                         write(fd, &cmd, sizeof(cmd));
334                         bytes = read(fd, &keyid, sizeof(keyid));
335                         if (bytes != sizeof(keyid)) {
336                                 ret = 1;
337                         }
338                         if (ret == 0) {
339                                 keyid = config.dbbackend->getfullkeyid(keyid);
340                                 cmd = sizeof(keyid);
341                                 write(fd, &cmd, sizeof(cmd));
342                                 write(fd, &keyid, sizeof(keyid));
343                         }
344                         break;
345                 case KEYD_CMD_KEYITER:
346                         cmd = KEYD_REPLY_OK;
347                         write(fd, &cmd, sizeof(cmd));
348                         config.dbbackend->iterate_keys(iteratefunc,
349                                         &fd);
350                         bytes = 0;
351                         write(fd, &bytes, sizeof(bytes));
352                         break;
353                 case KEYD_CMD_CLOSE:
354                         cmd = KEYD_REPLY_OK;
355                         write(fd, &cmd, sizeof(cmd));
356                         ret = 1;
357                         break;
358                 case KEYD_CMD_QUIT:
359                         cmd = KEYD_REPLY_OK;
360                         write(fd, &cmd, sizeof(cmd));
361                         logthing(LOGTHING_NOTICE,
362                                 "Exiting due to quit request.");
363                         ret = 1;
364                         trytocleanup();
365                         break;
366                 case KEYD_CMD_STATS:
367                         cmd = KEYD_REPLY_OK;
368                         write(fd, &cmd, sizeof(cmd));
369                         cmd = sizeof(*stats);
370                         write(fd, &cmd, sizeof(cmd));
371                         write(fd, stats,
372                                 sizeof(*stats));
373                         break;
374                 case KEYD_CMD_GETSKSHASH:
375                         cmd = KEYD_REPLY_OK;
376                         write(fd, &cmd, sizeof(cmd));
377                         bytes = read(fd, hash.hash, sizeof(hash.hash));
378                         if (bytes != sizeof(hash.hash)) {
379                                 ret = 1;
380                         }
381                         storebuf.offset = 0;
382                         if (ret == 0) {
383                                 logthing(LOGTHING_INFO,
384                                                 "Fetching by hash"
385                                                 ", result: %d",
386                                                 config.dbbackend->
387                                                 fetch_key_skshash(&hash,
388                                                         &key));
389                                 if (key != NULL) {
390                                         storebuf.size = 8192;
391                                         storebuf.buffer = malloc(8192);
392
393                                         flatten_publickey(key,
394                                                         &packets,
395                                                         &list_end);
396                                         write_openpgp_stream(buffer_putchar,
397                                                         &storebuf,
398                                                         packets);
399                                         logthing(LOGTHING_TRACE,
400                                                         "Sending %d bytes.",
401                                                         storebuf.offset);
402                                         write(fd, &storebuf.offset,
403                                                 sizeof(storebuf.offset));
404                                         write(fd, storebuf.buffer,
405                                                 storebuf.offset);
406
407                                         free(storebuf.buffer);
408                                         storebuf.buffer = NULL;
409                                         storebuf.size = storebuf.offset = 0;
410                                         free_packet_list(packets);
411                                         packets = list_end = NULL;
412                                         free_publickey(key);
413                                         key = NULL;
414                                 } else {
415                                         write(fd, &storebuf.offset,
416                                                 sizeof(storebuf.offset));
417                                 }
418                         }
419                         break;
420
421                 default:
422                         logthing(LOGTHING_ERROR, "Got unknown command: %d",
423                                         cmd);
424                         cmd = KEYD_REPLY_UNKNOWN_CMD;
425                         write(fd, &cmd, sizeof(cmd));
426                 }
427         }
428
429         return(ret);
430 }
431
432 int sock_close(int fd)
433 {
434         shutdown(fd, SHUT_RDWR);
435         return close(fd);
436 }
437
438 int sock_accept(int fd)
439 {
440         struct sockaddr_un sock;
441         socklen_t          socklen;
442         int    srv = -1;
443         int    ret = -1;
444
445         socklen = sizeof(sock);
446         srv = accept(fd, (struct sockaddr *) &sock, &socklen);
447         if (srv != -1) {
448                 ret = fcntl(srv, F_SETFD, 1);
449         }
450
451         if (ret != -1) {
452                 stats->connects++;
453                 while (!sock_do(srv)) ;
454                 sock_close(srv);
455         }
456
457         return 1;
458 }
459
460 static void usage(void)
461 {
462         puts("keyd " ONAK_VERSION " - backend key serving daemon for the "
463                 "onak PGP keyserver.\n");
464         puts("Usage:\n");
465         puts("\tkeyd [options]\n");
466         puts("\tOptions:\n:");
467         puts("-c <file> - use <file> as the config file");
468         puts("-f        - run in the foreground");
469         puts("-h        - show this help text");
470         exit(EXIT_FAILURE);
471 }
472
473 int main(int argc, char *argv[])
474 {
475         int fd = -1;
476         fd_set rfds;
477         char sockname[1024];
478         char *configfile = NULL;
479         bool foreground = false;
480         int optchar;
481
482         while ((optchar = getopt(argc, argv, "c:fh")) != -1 ) {
483                 switch (optchar) {
484                 case 'c':
485                         configfile = strdup(optarg);
486                         break;
487                 case 'f':
488                         foreground = true;
489                         break;
490                 case 'h':
491                 default:
492                         usage();
493                         break;
494                 }
495         }
496
497         readconfig(configfile);
498         free(configfile);
499         configfile = NULL;
500         initlogthing("keyd", config.logfile);
501         config.use_keyd = false;
502
503         if (!foreground) {
504                 daemonize();
505         }
506
507         catchsignals();
508         signal(SIGPIPE, SIG_IGN);
509
510
511         stats = calloc(1, sizeof(*stats));
512         if (!stats) {
513                 logthing(LOGTHING_ERROR,
514                         "Couldn't allocate memory for stats structure.");
515                 exit(EXIT_FAILURE);
516         }
517         stats->started = time(NULL);
518
519         snprintf(sockname, 1023, "%s/%s", config.db_dir, KEYD_SOCKET);
520         fd = sock_init(sockname);
521
522         if (fd != -1) {
523                 FD_ZERO(&rfds);
524                 FD_SET(fd, &rfds);
525
526                 config.dbbackend->initdb(false);
527
528                 logthing(LOGTHING_NOTICE, "Accepting connections.");
529                 while (!cleanup() && select(fd + 1, &rfds, NULL, NULL, NULL) != -1) {
530                         logthing(LOGTHING_INFO, "Accepted connection.");
531                         sock_accept(fd);
532                         FD_SET(fd, &rfds);
533                 }
534                 config.dbbackend->cleanupdb();
535                 sock_close(fd);
536                 unlink(sockname);
537         }
538
539         free(stats);
540
541         cleanuplogthing();
542         cleanupconfig();
543
544         return(EXIT_SUCCESS);
545 }