ebf142c3972ac69b83c33d675d4a3e6942111257
[onak.git] / keyd.c
1 /*
2  * keyd.c - key retrieval daemon
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 <getopt.h>
12 #include <signal.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <sys/select.h>
17 #include <sys/socket.h>
18 #include <sys/types.h>
19 #include <sys/un.h>
20 #include <unistd.h>
21
22 #include "charfuncs.h"
23 #include "cleanup.h"
24 #include "keyd.h"
25 #include "keydb.h"
26 #include "keyid.h"
27 #include "keystructs.h"
28 #include "log.h"
29 #include "mem.h"
30 #include "onak-conf.h"
31 #include "parsekey.h"
32
33 void daemonize(void)
34 {
35         pid_t pid;
36
37         pid = fork();
38
39         if (pid < 0) {
40                 logthing(LOGTHING_CRITICAL,
41                         "Failed to fork into background: %d (%s)",
42                         errno,
43                         strerror(errno));
44                 exit(EXIT_FAILURE);
45         } else if (pid > 0) {
46                 logthing(LOGTHING_INFO, "Backgrounded as pid %d.", pid);
47                 exit(EXIT_SUCCESS);
48         }
49
50         pid = setsid();
51
52         freopen("/dev/null", "r", stdin);
53         freopen("/dev/null", "w", stdout);
54         freopen("/dev/null", "w", stderr);
55
56         return;
57 }
58
59 void iteratefunc(void *ctx, struct openpgp_publickey *key)
60 {
61         struct openpgp_packet_list *packets = NULL;
62         struct openpgp_packet_list *list_end = NULL;
63         struct buffer_ctx           storebuf;
64         int                         ret = 0;
65         int                         *fd = (int *) ctx;
66
67         if (key != NULL) {
68                 storebuf.offset = 0;
69                 storebuf.size = 8192;
70                 storebuf.buffer = malloc(8192);
71
72                 logthing(LOGTHING_TRACE,
73                                 "Iterating over 0x%016" PRIX64 ".",
74                                 get_keyid(key));
75
76                 flatten_publickey(key,
77                                 &packets,
78                                 &list_end);
79                 write_openpgp_stream(buffer_putchar,
80                                 &storebuf,
81                                 packets);
82                 logthing(LOGTHING_TRACE,
83                                 "Sending %d bytes.",
84                                 storebuf.offset);
85                 ret = write(*fd, &storebuf.offset,
86                         sizeof(storebuf.offset));
87                 if (ret != 0) {
88                         write(*fd, storebuf.buffer,
89                                 storebuf.offset);
90                 }
91
92                 free(storebuf.buffer);
93                 storebuf.buffer = NULL;
94                 storebuf.size = storebuf.offset = 0;
95                 free_packet_list(packets);
96                 packets = list_end = NULL;
97         }
98
99         return;
100 }
101
102 int sock_init(const char *sockname)
103 {
104         struct sockaddr_un sock;
105         int                fd = -1;
106         int                ret = -1;
107
108         fd = socket(PF_UNIX, SOCK_STREAM, 0);
109         if (fd != -1) {
110                 ret = fcntl(fd, F_SETFD, 1);
111         }
112
113         if (ret != -1) {
114                 sock.sun_family = AF_UNIX;
115                 strncpy(sock.sun_path, sockname, sizeof(sock.sun_path) - 1);
116                 unlink(sockname);
117                 ret = bind(fd, (struct sockaddr *) &sock, sizeof(sock));
118         }
119
120         if (ret != -1) {
121                 ret = listen(fd, 5);
122         }
123         
124         return fd;
125 }
126
127 int sock_do(int fd)
128 {
129         uint32_t cmd = KEYD_CMD_UNKNOWN;
130         ssize_t  bytes = 0;
131         ssize_t  count = 0;
132         int      ret = 0;
133         uint64_t keyid = 0;
134         char     *search = NULL;
135         struct openpgp_publickey *key = NULL;
136         struct openpgp_packet_list *packets = NULL;
137         struct openpgp_packet_list *list_end = NULL;
138         struct buffer_ctx storebuf;
139
140         /*
141          * Get the command from the client.
142          */
143         bytes = read(fd, &cmd, sizeof(cmd));
144
145         logthing(LOGTHING_DEBUG, "Read %d bytes, command: %d", bytes, cmd);
146
147         if (bytes != sizeof(cmd)) {
148                 ret = 1;
149         }
150         
151         if (ret == 0) {
152                 switch (cmd) {
153                 case KEYD_CMD_VERSION:
154                         cmd = KEYD_REPLY_OK;
155                         write(fd, &cmd, sizeof(cmd));
156                         cmd = sizeof(keyd_version);
157                         write(fd, &cmd, sizeof(cmd));
158                         write(fd, &keyd_version, sizeof(keyd_version));
159                         break;
160                 case KEYD_CMD_GET:
161                         cmd = KEYD_REPLY_OK;
162                         write(fd, &cmd, sizeof(cmd));
163                         bytes = read(fd, &keyid, sizeof(keyid));
164                         if (bytes != sizeof(keyid)) {
165                                 ret = 1;
166                         }
167                         storebuf.offset = 0;
168                         if (ret == 0) {
169                                 logthing(LOGTHING_INFO,
170                                                 "Fetching 0x%" PRIX64
171                                                 ", result: %d",
172                                                 keyid,
173                                                 config.dbbackend->
174                                                 fetch_key(keyid, &key, false));
175                                 if (key != NULL) {
176                                         storebuf.size = 8192;
177                                         storebuf.buffer = malloc(8192);
178
179                                         flatten_publickey(key,
180                                                         &packets,
181                                                         &list_end);
182                                         write_openpgp_stream(buffer_putchar,
183                                                         &storebuf,
184                                                         packets);
185                                         logthing(LOGTHING_TRACE,
186                                                         "Sending %d bytes.",
187                                                         storebuf.offset);
188                                         write(fd, &storebuf.offset,
189                                                 sizeof(storebuf.offset));
190                                         write(fd, storebuf.buffer,
191                                                 storebuf.offset);
192
193                                         free(storebuf.buffer);
194                                         storebuf.buffer = NULL;
195                                         storebuf.size = storebuf.offset = 0;
196                                         free_packet_list(packets);
197                                         packets = list_end = NULL;
198                                         free_publickey(key);
199                                         key = NULL;
200                                 } else {
201                                         write(fd, &storebuf.offset,
202                                                 sizeof(storebuf.offset));
203                                 }
204                         }
205                         break;
206                 case KEYD_CMD_GETTEXT:
207                         cmd = KEYD_REPLY_OK;
208                         write(fd, &cmd, sizeof(cmd));
209                         bytes = read(fd, &count, sizeof(count));
210                         if (bytes != sizeof(count)) {
211                                 ret = 1;
212                         }
213                         storebuf.offset = 0;
214                         if (ret == 0) {
215                                 search = malloc(count+1);
216                                 read(fd, search, count);
217                                 search[count] = 0;
218                                 logthing(LOGTHING_INFO,
219                                                 "Fetching %s, result: %d",
220                                                 search,
221                                                 config.dbbackend->
222                                                 fetch_key_text(search, &key));
223                                 if (key != NULL) {
224                                         storebuf.size = 8192;
225                                         storebuf.buffer = malloc(8192);
226
227                                         flatten_publickey(key,
228                                                         &packets,
229                                                         &list_end);
230                                         write_openpgp_stream(buffer_putchar,
231                                                         &storebuf,
232                                                         packets);
233                                         logthing(LOGTHING_TRACE,
234                                                         "Sending %d bytes.",
235                                                         storebuf.offset);
236                                         write(fd, &storebuf.offset,
237                                                 sizeof(storebuf.offset));
238                                         write(fd, storebuf.buffer,
239                                                 storebuf.offset);
240
241                                         free(storebuf.buffer);
242                                         storebuf.buffer = NULL;
243                                         storebuf.size = storebuf.offset = 0;
244                                         free_packet_list(packets);
245                                         packets = list_end = NULL;
246                                         free_publickey(key);
247                                         key = NULL;
248                                 } else {
249                                         write(fd, &storebuf.offset,
250                                                 sizeof(storebuf.offset));
251                                 }
252                         }
253                         break;
254                 case KEYD_CMD_STORE:
255                         cmd = KEYD_REPLY_OK;
256                         write(fd, &cmd, sizeof(cmd));
257                         storebuf.offset = 0;
258                         bytes = read(fd, &storebuf.size,
259                                         sizeof(storebuf.size));
260                         logthing(LOGTHING_TRACE, "Reading %d bytes.",
261                                         storebuf.size);
262                         if (bytes != sizeof(storebuf.size)) {
263                                 ret = 1;
264                         }
265                         if (ret == 0 && storebuf.size > 0) {
266                                 storebuf.buffer = malloc(storebuf.size);
267                                 bytes = count = 0;
268                                 while (bytes >= 0 && count < storebuf.size) {
269                                         bytes = read(fd,
270                                                 &storebuf.buffer[count],
271                                                 storebuf.size - count);
272                                         logthing(LOGTHING_TRACE,
273                                                         "Read %d bytes.",
274                                                         bytes);
275                                         count += bytes;
276                                 }
277                                 read_openpgp_stream(buffer_fetchchar,
278                                                 &storebuf,
279                                                 &packets,
280                                                 0);
281                                 parse_keys(packets, &key);
282                                 config.dbbackend->store_key(key, false, false);
283                                 free_packet_list(packets);
284                                 packets = NULL;
285                                 free_publickey(key);
286                                 key = NULL;
287                                 free(storebuf.buffer);
288                                 storebuf.buffer = NULL;
289                                 storebuf.size = storebuf.offset = 0;
290                         }
291                         break;
292                 case KEYD_CMD_DELETE:
293                         cmd = KEYD_REPLY_OK;
294                         write(fd, &cmd, sizeof(cmd));
295                         bytes = read(fd, &keyid, sizeof(keyid));
296                         if (bytes != sizeof(keyid)) {
297                                 ret = 1;
298                         }
299                         if (ret == 0) {
300                                 logthing(LOGTHING_INFO,
301                                                 "Deleting 0x%" PRIX64
302                                                 ", result: %d",
303                                                 keyid,
304                                                 config.dbbackend->delete_key(
305                                                         keyid, false));
306                         }
307                         break;
308                 case KEYD_CMD_GETFULLKEYID:
309                         cmd = KEYD_REPLY_OK;
310                         write(fd, &cmd, sizeof(cmd));
311                         bytes = read(fd, &keyid, sizeof(keyid));
312                         if (bytes != sizeof(keyid)) {
313                                 ret = 1;
314                         }
315                         if (ret == 0) {
316                                 keyid = config.dbbackend->getfullkeyid(keyid);
317                                 cmd = sizeof(keyid);
318                                 write(fd, &cmd, sizeof(cmd));
319                                 write(fd, &keyid, sizeof(keyid));
320                         }
321                         break;
322                 case KEYD_CMD_KEYITER:
323                         cmd = KEYD_REPLY_OK;
324                         write(fd, &cmd, sizeof(cmd));
325                         config.dbbackend->iterate_keys(iteratefunc,
326                                         &fd);
327                         bytes = 0;
328                         write(fd, &bytes, sizeof(bytes));
329                         break;
330                 case KEYD_CMD_CLOSE:
331                         cmd = KEYD_REPLY_OK;
332                         write(fd, &cmd, sizeof(cmd));
333                         ret = 1;
334                         break;
335                 case KEYD_CMD_QUIT:
336                         cmd = KEYD_REPLY_OK;
337                         write(fd, &cmd, sizeof(cmd));
338                         logthing(LOGTHING_NOTICE,
339                                 "Exiting due to quit request.");
340                         ret = 1;
341                         trytocleanup();
342                         break;
343                 default:
344                         logthing(LOGTHING_ERROR, "Got unknown command: %d",
345                                         cmd);
346                         cmd = KEYD_REPLY_UNKNOWN_CMD;
347                         write(fd, &cmd, sizeof(cmd));
348                 }
349         }
350
351         return(ret);
352 }
353
354 int sock_close(int fd)
355 {
356         shutdown(fd, SHUT_RDWR);
357         return close(fd);
358 }
359
360 int sock_accept(int fd)
361 {
362         struct sockaddr_un sock;
363         socklen_t          socklen;
364         int    srv = -1;
365         int    ret = -1;
366
367         socklen = sizeof(sock);
368         srv = accept(fd, (struct sockaddr *) &sock, &socklen);
369         if (srv != -1) {
370                 ret = fcntl(srv, F_SETFD, 1);
371         }
372
373         if (ret != -1) {
374                 while (!sock_do(srv)) ;
375                 sock_close(srv);
376         }
377
378         return 1;
379 }
380
381 int main(int argc, char *argv[])
382 {
383         int fd = -1;
384         fd_set rfds;
385         char sockname[1024];
386         char *configfile = NULL;
387         bool foreground = false;
388         int optchar;
389
390         while ((optchar = getopt(argc, argv, "c:f")) != -1 ) {
391                 switch (optchar) {
392                 case 'c':
393                         configfile = strdup(optarg);
394                         break;
395                 case 'f':
396                         foreground = true;
397                         break;
398                 }
399         }
400
401         readconfig(configfile);
402         free(configfile);
403         configfile = NULL;
404         initlogthing("keyd", config.logfile);
405         config.use_keyd = false;
406
407         if (!foreground) {
408                 daemonize();
409         }
410
411         catchsignals();
412         signal(SIGPIPE, SIG_IGN);
413
414         snprintf(sockname, 1023, "%s/%s", config.db_dir, KEYD_SOCKET);
415         fd = sock_init(sockname);
416
417         if (fd != -1) {
418                 FD_ZERO(&rfds);
419                 FD_SET(fd, &rfds);
420
421                 config.dbbackend->initdb(false);
422
423                 logthing(LOGTHING_NOTICE, "Accepting connections.");
424                 while (!cleanup() && select(fd + 1, &rfds, NULL, NULL, NULL) != -1) {
425                         logthing(LOGTHING_INFO, "Accepted connection.");
426                         sock_accept(fd);
427                         FD_SET(fd, &rfds);
428                 }
429                 config.dbbackend->cleanupdb();
430                 sock_close(fd);
431                 unlink(sockname);
432         }
433
434         cleanuplogthing();
435         cleanupconfig();
436
437         return(EXIT_SUCCESS);
438 }