Add keyd backend (persistant database access over Unix socket)
[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 "keystructs.h"
23 #include "log.h"
24 #include "mem.h"
25 #include "onak-conf.h"
26 #include "parsekey.h"
27
28 int sock_init(const char *sockname)
29 {
30         struct sockaddr_un sock;
31         int                fd = -1;
32         int                ret = -1;
33
34         fd = socket(PF_UNIX, SOCK_STREAM, 0);
35         if (fd != -1) {
36                 ret = fcntl(fd, F_SETFD, 1);
37         }
38
39         if (ret != -1) {
40                 sock.sun_family = AF_UNIX;
41                 strncpy(sock.sun_path, sockname, sizeof(sock.sun_path) - 1);
42                 unlink(sockname);
43                 ret = bind(fd, (struct sockaddr *) &sock, sizeof(sock));
44         }
45
46         if (ret != -1) {
47                 ret = listen(fd, 5);
48         }
49         
50         return fd;
51 }
52
53 int sock_do(int fd)
54 {
55         int      cmd = KEYD_CMD_UNKNOWN;
56         ssize_t  bytes = 0;
57         ssize_t  count = 0;
58         int      ret = 0;
59         uint64_t keyid = 0;
60         char     *search = NULL;
61         struct openpgp_publickey *key = NULL;
62         struct openpgp_packet_list *packets = NULL;
63         struct openpgp_packet_list *list_end = NULL;
64         struct buffer_ctx storebuf;
65
66         /*
67          * Get the command from the client.
68          */
69         bytes = read(fd, &cmd, sizeof(cmd));
70
71         logthing(LOGTHING_DEBUG, "Read %d bytes, command: %d", bytes, cmd);
72
73         if (bytes != sizeof(cmd)) {
74                 ret = 1;
75         }
76         
77         if (ret == 0) {
78                 switch (cmd) {
79                 case KEYD_CMD_VERSION:
80                         cmd = KEYD_REPLY_OK;
81                         write(fd, &cmd, sizeof(cmd));
82                         write(fd, &keyd_version, sizeof(keyd_version));
83                         break;
84                 case KEYD_CMD_GET:
85                         cmd = KEYD_REPLY_OK;
86                         write(fd, &cmd, sizeof(cmd));
87                         bytes = read(fd, &keyid, sizeof(keyid));
88                         if (bytes != sizeof(keyid)) {
89                                 ret = 1;
90                         }
91                         storebuf.offset = 0;
92                         if (ret == 0) {
93                                 logthing(LOGTHING_INFO,
94                                                 "Fetching 0x%llX, result: %d",
95                                                 keyid,
96                                                 fetch_key(keyid, &key, false));
97                                 if (key != NULL) {
98                                         storebuf.size = 8192;
99                                         storebuf.buffer = malloc(8192);
100
101                                         flatten_publickey(key,
102                                                         &packets,
103                                                         &list_end);
104                                         write_openpgp_stream(buffer_putchar,
105                                                         &storebuf,
106                                                         packets);
107                                         logthing(LOGTHING_TRACE,
108                                                         "Sending %d bytes.",
109                                                         storebuf.offset);
110                                         write(fd, &storebuf.offset,
111                                                 sizeof(storebuf.offset));
112                                         write(fd, storebuf.buffer,
113                                                 storebuf.offset);
114
115                                         free(storebuf.buffer);
116                                         storebuf.buffer = NULL;
117                                         storebuf.size = storebuf.offset = 0;
118                                         free_packet_list(packets);
119                                         packets = list_end = NULL;
120                                         free_publickey(key);
121                                         key = NULL;
122                                 } else {
123                                         write(fd, &storebuf.offset,
124                                                 sizeof(storebuf.offset));
125                                 }
126                         }
127                         break;
128                 case KEYD_CMD_GETTEXT:
129                         cmd = KEYD_REPLY_OK;
130                         write(fd, &cmd, sizeof(cmd));
131                         bytes = read(fd, &count, sizeof(count));
132                         if (bytes != sizeof(count)) {
133                                 ret = 1;
134                         }
135                         storebuf.offset = 0;
136                         if (ret == 0) {
137                                 search = malloc(count+1);
138                                 read(fd, search, count);
139                                 search[count] = 0;
140                                 logthing(LOGTHING_INFO,
141                                                 "Fetching %s, result: %d",
142                                                 search,
143                                                 fetch_key_text(search, &key));
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_STORE:
176                         cmd = KEYD_REPLY_OK;
177                         write(fd, &cmd, sizeof(cmd));
178                         storebuf.offset = 0;
179                         bytes = read(fd, &storebuf.size,
180                                         sizeof(storebuf.size));
181                         logthing(LOGTHING_TRACE, "Reading %d bytes.",
182                                         storebuf.size);
183                         if (bytes != sizeof(storebuf.size)) {
184                                 ret = 1;
185                         }
186                         if (ret == 0 && storebuf.size > 0) {
187                                 storebuf.buffer = malloc(storebuf.size);
188                                 bytes = count = 0;
189                                 while (bytes >= 0 && count < storebuf.size) {
190                                         bytes = read(fd,
191                                                 &storebuf.buffer[count],
192                                                 storebuf.size - count);
193                                         logthing(LOGTHING_TRACE,
194                                                         "Read %d bytes.",
195                                                         bytes);
196                                         count += bytes;
197                                 }
198                                 read_openpgp_stream(buffer_fetchchar,
199                                                 &storebuf,
200                                                 &packets,
201                                                 0);
202                                 parse_keys(packets, &key);
203                                 store_key(key, false, false);
204                                 free_packet_list(packets);
205                                 packets = NULL;
206                                 free_publickey(key);
207                                 key = NULL;
208                                 free(storebuf.buffer);
209                                 storebuf.buffer = NULL;
210                                 storebuf.size = storebuf.offset = 0;
211                         }
212                         break;
213                 case KEYD_CMD_DELETE:
214                         cmd = KEYD_REPLY_OK;
215                         write(fd, &cmd, sizeof(cmd));
216                         bytes = read(fd, &keyid, sizeof(keyid));
217                         if (bytes != sizeof(keyid)) {
218                                 ret = 1;
219                         }
220                         if (ret == 0) {
221                                 logthing(LOGTHING_INFO,
222                                                 "Deleting 0x%llX, result: %d",
223                                                 keyid,
224                                                 delete_key(keyid, false));
225                         }
226                         break;
227                 case KEYD_CMD_GETFULLKEYID:
228                         cmd = KEYD_REPLY_OK;
229                         write(fd, &cmd, sizeof(cmd));
230                         bytes = read(fd, &keyid, sizeof(keyid));
231                         if (bytes != sizeof(keyid)) {
232                                 ret = 1;
233                         }
234                         if (ret == 0) {
235                                 keyid = getfullkeyid(keyid);
236                                 write(fd, &keyid, sizeof(keyid));
237                         }
238                         break;
239                 case KEYD_CMD_CLOSE:
240                         ret = 1;
241                         break;
242                 case KEYD_CMD_QUIT:
243                         trytocleanup();
244                         break;
245                 default:
246                         logthing(LOGTHING_ERROR, "Got unknown command: %d",
247                                         cmd);
248                         cmd = KEYD_REPLY_UNKNOWN_CMD;
249                         write(fd, &cmd, sizeof(cmd));
250                 }
251         }
252
253         return(ret);
254 }
255
256 int sock_close(int fd)
257 {
258         return shutdown(fd, SHUT_RDWR);
259 }
260
261 int sock_accept(int fd)
262 {
263         struct sockaddr_un sock;
264         socklen_t          socklen;
265         int    srv = -1;
266         int    ret = -1;
267
268         socklen = sizeof(sock);
269         srv = accept(fd, (struct sockaddr *) &sock, &socklen);
270         if (srv != -1) {
271                 ret = fcntl(srv, F_SETFD, 1);
272         }
273
274         if (ret != -1) {
275                 while (!sock_do(srv)) ;
276                 sock_close(srv);
277         }
278
279         return 1;
280 }
281
282 int main(int argc, char *argv[])
283 {
284         int fd = -1;
285         fd_set rfds;
286         char sockname[1024];
287
288         readconfig(NULL);
289         initlogthing("keyd", config.logfile);
290
291         catchsignals();
292         
293         snprintf(sockname, 1023, "%s/%s", config.db_dir, KEYD_SOCKET);
294         fd = sock_init(sockname);
295
296         if (fd != -1) {
297                 FD_ZERO(&rfds);
298                 FD_SET(fd, &rfds);
299
300                 initdb(false);
301
302                 logthing(LOGTHING_NOTICE, "Accepting connections.");
303                 while (!cleanup() && select(fd + 1, &rfds, NULL, NULL, NULL) != -1) {
304                         logthing(LOGTHING_INFO, "Accepted connection.");
305                         sock_accept(fd);
306                         FD_SET(fd, &rfds);
307                 }
308                 cleanupdb();
309                 sock_close(fd);
310                 unlink(sockname);
311         }
312
313         cleanuplogthing();
314         cleanupconfig();
315         
316         return(EXIT_SUCCESS);
317 }