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