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