Add key iteration functionality to keydb backends.
[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                                                 fetch_key(keyid, &key, false));
141                                 if (key != NULL) {
142                                         storebuf.size = 8192;
143                                         storebuf.buffer = malloc(8192);
144
145                                         flatten_publickey(key,
146                                                         &packets,
147                                                         &list_end);
148                                         write_openpgp_stream(buffer_putchar,
149                                                         &storebuf,
150                                                         packets);
151                                         logthing(LOGTHING_TRACE,
152                                                         "Sending %d bytes.",
153                                                         storebuf.offset);
154                                         write(fd, &storebuf.offset,
155                                                 sizeof(storebuf.offset));
156                                         write(fd, storebuf.buffer,
157                                                 storebuf.offset);
158
159                                         free(storebuf.buffer);
160                                         storebuf.buffer = NULL;
161                                         storebuf.size = storebuf.offset = 0;
162                                         free_packet_list(packets);
163                                         packets = list_end = NULL;
164                                         free_publickey(key);
165                                         key = NULL;
166                                 } else {
167                                         write(fd, &storebuf.offset,
168                                                 sizeof(storebuf.offset));
169                                 }
170                         }
171                         break;
172                 case KEYD_CMD_GETTEXT:
173                         cmd = KEYD_REPLY_OK;
174                         write(fd, &cmd, sizeof(cmd));
175                         bytes = read(fd, &count, sizeof(count));
176                         if (bytes != sizeof(count)) {
177                                 ret = 1;
178                         }
179                         storebuf.offset = 0;
180                         if (ret == 0) {
181                                 search = malloc(count+1);
182                                 read(fd, search, count);
183                                 search[count] = 0;
184                                 logthing(LOGTHING_INFO,
185                                                 "Fetching %s, result: %d",
186                                                 search,
187                                                 fetch_key_text(search, &key));
188                                 if (key != NULL) {
189                                         storebuf.size = 8192;
190                                         storebuf.buffer = malloc(8192);
191
192                                         flatten_publickey(key,
193                                                         &packets,
194                                                         &list_end);
195                                         write_openpgp_stream(buffer_putchar,
196                                                         &storebuf,
197                                                         packets);
198                                         logthing(LOGTHING_TRACE,
199                                                         "Sending %d bytes.",
200                                                         storebuf.offset);
201                                         write(fd, &storebuf.offset,
202                                                 sizeof(storebuf.offset));
203                                         write(fd, storebuf.buffer,
204                                                 storebuf.offset);
205
206                                         free(storebuf.buffer);
207                                         storebuf.buffer = NULL;
208                                         storebuf.size = storebuf.offset = 0;
209                                         free_packet_list(packets);
210                                         packets = list_end = NULL;
211                                         free_publickey(key);
212                                         key = NULL;
213                                 } else {
214                                         write(fd, &storebuf.offset,
215                                                 sizeof(storebuf.offset));
216                                 }
217                         }
218                         break;
219                 case KEYD_CMD_STORE:
220                         cmd = KEYD_REPLY_OK;
221                         write(fd, &cmd, sizeof(cmd));
222                         storebuf.offset = 0;
223                         bytes = read(fd, &storebuf.size,
224                                         sizeof(storebuf.size));
225                         logthing(LOGTHING_TRACE, "Reading %d bytes.",
226                                         storebuf.size);
227                         if (bytes != sizeof(storebuf.size)) {
228                                 ret = 1;
229                         }
230                         if (ret == 0 && storebuf.size > 0) {
231                                 storebuf.buffer = malloc(storebuf.size);
232                                 bytes = count = 0;
233                                 while (bytes >= 0 && count < storebuf.size) {
234                                         bytes = read(fd,
235                                                 &storebuf.buffer[count],
236                                                 storebuf.size - count);
237                                         logthing(LOGTHING_TRACE,
238                                                         "Read %d bytes.",
239                                                         bytes);
240                                         count += bytes;
241                                 }
242                                 read_openpgp_stream(buffer_fetchchar,
243                                                 &storebuf,
244                                                 &packets,
245                                                 0);
246                                 parse_keys(packets, &key);
247                                 store_key(key, false, false);
248                                 free_packet_list(packets);
249                                 packets = NULL;
250                                 free_publickey(key);
251                                 key = NULL;
252                                 free(storebuf.buffer);
253                                 storebuf.buffer = NULL;
254                                 storebuf.size = storebuf.offset = 0;
255                         }
256                         break;
257                 case KEYD_CMD_DELETE:
258                         cmd = KEYD_REPLY_OK;
259                         write(fd, &cmd, sizeof(cmd));
260                         bytes = read(fd, &keyid, sizeof(keyid));
261                         if (bytes != sizeof(keyid)) {
262                                 ret = 1;
263                         }
264                         if (ret == 0) {
265                                 logthing(LOGTHING_INFO,
266                                                 "Deleting 0x%llX, result: %d",
267                                                 keyid,
268                                                 delete_key(keyid, false));
269                         }
270                         break;
271                 case KEYD_CMD_GETFULLKEYID:
272                         cmd = KEYD_REPLY_OK;
273                         write(fd, &cmd, sizeof(cmd));
274                         bytes = read(fd, &keyid, sizeof(keyid));
275                         if (bytes != sizeof(keyid)) {
276                                 ret = 1;
277                         }
278                         if (ret == 0) {
279                                 keyid = getfullkeyid(keyid);
280                                 write(fd, &keyid, sizeof(keyid));
281                         }
282                         break;
283                 case KEYD_CMD_KEYITER:
284                         cmd = KEYD_REPLY_OK;
285                         write(fd, &cmd, sizeof(cmd));
286                         iterate_keys(iteratefunc, (void *) fd);
287                         bytes = 0;
288                         write(fd, &bytes, sizeof(bytes));
289                         break;
290                 case KEYD_CMD_CLOSE:
291                         ret = 1;
292                         break;
293                 case KEYD_CMD_QUIT:
294                         trytocleanup();
295                         break;
296                 default:
297                         logthing(LOGTHING_ERROR, "Got unknown command: %d",
298                                         cmd);
299                         cmd = KEYD_REPLY_UNKNOWN_CMD;
300                         write(fd, &cmd, sizeof(cmd));
301                 }
302         }
303
304         return(ret);
305 }
306
307 int sock_close(int fd)
308 {
309         return shutdown(fd, SHUT_RDWR);
310 }
311
312 int sock_accept(int fd)
313 {
314         struct sockaddr_un sock;
315         socklen_t          socklen;
316         int    srv = -1;
317         int    ret = -1;
318
319         socklen = sizeof(sock);
320         srv = accept(fd, (struct sockaddr *) &sock, &socklen);
321         if (srv != -1) {
322                 ret = fcntl(srv, F_SETFD, 1);
323         }
324
325         if (ret != -1) {
326                 while (!sock_do(srv)) ;
327                 sock_close(srv);
328         }
329
330         return 1;
331 }
332
333 int main(int argc, char *argv[])
334 {
335         int fd = -1;
336         fd_set rfds;
337         char sockname[1024];
338
339         readconfig(NULL);
340         initlogthing("keyd", config.logfile);
341
342         catchsignals();
343         
344         snprintf(sockname, 1023, "%s/%s", config.db_dir, KEYD_SOCKET);
345         fd = sock_init(sockname);
346
347         if (fd != -1) {
348                 FD_ZERO(&rfds);
349                 FD_SET(fd, &rfds);
350
351                 initdb(false);
352
353                 logthing(LOGTHING_NOTICE, "Accepting connections.");
354                 while (!cleanup() && select(fd + 1, &rfds, NULL, NULL, NULL) != -1) {
355                         logthing(LOGTHING_INFO, "Accepted connection.");
356                         sock_accept(fd);
357                         FD_SET(fd, &rfds);
358                 }
359                 cleanupdb();
360                 sock_close(fd);
361                 unlink(sockname);
362         }
363
364         cleanuplogthing();
365         cleanupconfig();
366         
367         return(EXIT_SUCCESS);
368 }