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