Add keyd backend (persistant database access over Unix socket)
[onak.git] / keydb_keyd.c
1 /*
2  * keydb_keyd.c - Routines to talk to keyd backend.
3  *
4  * Jonathan McDowell <noodles@earth.li>
5  *
6  * Copyright 2004 Project Purple
7  */
8
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.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 "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 /**
30  *      keyd_fd - our file descriptor for the socket connection to keyd.
31  */
32 static int keyd_fd = -1;
33
34 /**
35  *      initdb - Initialize the key database.
36  *      @readonly: If we'll only be reading the DB, not writing to it.
37  *
38  *      This function should be called before any of the other functions in
39  *      this file are called in order to allow the DB to be initialized ready
40  *      for access.
41  */
42 void initdb(bool readonly)
43 {
44         struct sockaddr_un sock;
45         int                cmd = KEYD_CMD_UNKNOWN;
46         int                reply = KEYD_REPLY_UNKNOWN_CMD;
47         ssize_t            count;
48
49         keyd_fd = socket(PF_UNIX, SOCK_STREAM, 0);
50         if (keyd_fd < 0) {
51                 logthing(LOGTHING_CRITICAL,
52                                 "Couldn't open socket: %s (%d)",
53                                 strerror(errno),
54                                 errno);
55                 exit(EXIT_FAILURE);
56         }
57
58         sock.sun_family = AF_UNIX;
59         snprintf(sock.sun_path, sizeof(sock.sun_path) - 1, "%s/%s",
60                         config.db_dir,
61                         KEYD_SOCKET);
62         if (connect(keyd_fd, (struct sockaddr *) &sock, sizeof(sock)) < 0) {
63                 logthing(LOGTHING_CRITICAL,
64                                 "Couldn't connect to socket %s: %s (%d)",
65                                 sock.sun_path,
66                                 strerror(errno),
67                                 errno);
68                 exit(EXIT_FAILURE);
69         }
70
71         cmd = KEYD_CMD_VERSION;
72         if (write(keyd_fd, &cmd, sizeof(cmd)) != sizeof(cmd)) {
73                 logthing(LOGTHING_CRITICAL,
74                                 "Couldn't write version cmd: %s (%d)",
75                                 strerror(errno),
76                                 errno);
77         } else {
78                 count = read(keyd_fd, &reply, sizeof(reply));
79                 if (count == sizeof(reply)) {
80                         if (reply == KEYD_REPLY_OK) {
81                                 count = read(keyd_fd, &reply, sizeof(reply));
82                                 logthing(LOGTHING_DEBUG,
83                                                 "keyd protocol version %d",
84                                                 reply);
85                                 if (reply != keyd_version) {
86                                         logthing(LOGTHING_CRITICAL,
87                                                 "Error! keyd protocol version "
88                                                 "mismatch. (us = %d, it = %d)",
89                                                 keyd_version, reply);
90                                 }
91                         }
92                 }
93         }
94
95         return;
96 }
97
98 /**
99  *      cleanupdb - De-initialize the key database.
100  *
101  *      This function should be called upon program exit to allow the DB to
102  *      cleanup after itself.
103  */
104 void cleanupdb(void)
105 {
106         if (shutdown(keyd_fd, SHUT_RDWR) < 0) {
107                 logthing(LOGTHING_NOTICE, "Error shutting down socket: %d",
108                                 errno);
109         }
110         keyd_fd = -1;
111
112         return;
113 }
114
115
116 /**
117  *      starttrans - Start a transaction.
118  *
119  *      Start a transaction. Intended to be used if we're about to perform many
120  *      operations on the database to help speed it all up, or if we want
121  *      something to only succeed if all relevant operations are successful.
122  */
123 bool starttrans(void)
124 {
125         return true;
126 }
127
128 /**
129  *      endtrans - End a transaction.
130  *
131  *      Ends a transaction.
132  */
133 void endtrans(void)
134 {
135         return;
136 }
137
138 /**
139  *      fetch_key - Given a keyid fetch the key from storage.
140  *      @keyid: The keyid to fetch.
141  *      @publickey: A pointer to a structure to return the key in.
142  *      @intrans: If we're already in a transaction.
143  *
144  *      This function returns a public key from whatever storage mechanism we
145  *      are using.
146  *
147  *      TODO: What about keyid collisions? Should we use fingerprint instead?
148  */
149 int fetch_key(uint64_t keyid, struct openpgp_publickey **publickey,
150                 bool intrans)
151 {
152         struct buffer_ctx           keybuf;
153         struct openpgp_packet_list *packets = NULL;
154         int                         cmd = KEYD_CMD_GET;
155         ssize_t                     bytes = 0;
156         ssize_t                     count = 0;
157
158         write(keyd_fd, &cmd, sizeof(cmd));
159         read(keyd_fd, &cmd, sizeof(cmd));
160         if (cmd == KEYD_REPLY_OK) {
161                 write(keyd_fd, &keyid, sizeof(keyid));
162                 keybuf.offset = 0;
163                 read(keyd_fd, &keybuf.size, sizeof(keybuf.size));
164                 if (keybuf.size > 0) {
165                         keybuf.buffer = malloc(keybuf.size);
166                         bytes = count = 0;
167                         logthing(LOGTHING_TRACE,
168                                         "Getting %d bytes of key data.",
169                                         keybuf.size);
170                         while (bytes >= 0 && count < keybuf.size) {
171                                 bytes = read(keyd_fd, &keybuf.buffer[count],
172                                                 keybuf.size - count);
173                                 logthing(LOGTHING_TRACE,
174                                                 "Read %d bytes.", bytes);
175                                 count += bytes;
176                         }
177                         read_openpgp_stream(buffer_fetchchar, &keybuf,
178                                         &packets, 0);
179                         parse_keys(packets, publickey);
180                         free_packet_list(packets);
181                         packets = NULL;
182                         free(keybuf.buffer);
183                         keybuf.buffer = NULL;
184                         keybuf.size = 0;
185                 }
186         }
187         
188         return (count > 0) ? 1 : 0;
189 }
190
191 /**
192  *      store_key - Takes a key and stores it.
193  *      @publickey: A pointer to the public key to store.
194  *      @intrans: If we're already in a transaction.
195  *      @update: If true the key exists and should be updated.
196  *
197  *      This function stores a public key in whatever storage mechanism we are
198  *      using. intrans indicates if we're already in a transaction so don't
199  *      need to start one. update indicates if the key already exists and is
200  *      just being updated.
201  *
202  *      TODO: Do we store multiple keys of the same id? Or only one and replace
203  *      it?
204  */
205 int store_key(struct openpgp_publickey *publickey, bool intrans, bool update)
206 {
207         struct buffer_ctx           keybuf;
208         struct openpgp_packet_list *packets = NULL;
209         struct openpgp_packet_list *list_end = NULL;
210         struct openpgp_publickey   *next = NULL;
211         int                         cmd = KEYD_CMD_STORE;
212         uint64_t                    keyid;
213
214         keyid = get_keyid(publickey);
215         
216         if (update) {
217                 delete_key(keyid, false);
218         }
219
220         write(keyd_fd, &cmd, sizeof(cmd));
221         read(keyd_fd, &cmd, sizeof(cmd));
222         if (cmd == KEYD_REPLY_OK) {
223                 keybuf.offset = 0;
224                 keybuf.size = 8192;
225                 keybuf.buffer = malloc(keybuf.size);
226
227                 next = publickey->next;
228                 publickey->next = NULL;
229                 flatten_publickey(publickey,
230                                 &packets,
231                                 &list_end);
232                 publickey->next = next;
233
234                 write_openpgp_stream(buffer_putchar, &keybuf, packets);
235                 logthing(LOGTHING_TRACE, "Sending %d bytes.", keybuf.offset);
236                 write(keyd_fd, &keybuf.offset, sizeof(keybuf.offset));
237                 write(keyd_fd, keybuf.buffer, keybuf.offset);
238
239                 free_packet_list(packets);
240                 packets = list_end = NULL;
241                 free(keybuf.buffer);
242                 keybuf.buffer = NULL;
243                 keybuf.size = keybuf.offset = 0;
244         }
245         
246         return 0;
247 }
248
249 /**
250  *      delete_key - Given a keyid delete the key from storage.
251  *      @keyid: The keyid to delete.
252  *      @intrans: If we're already in a transaction.
253  *
254  *      This function deletes a public key from whatever storage mechanism we
255  *      are using. Returns 0 if the key existed.
256  */
257 int delete_key(uint64_t keyid, bool intrans)
258 {
259         int cmd = KEYD_CMD_DELETE;
260
261         write(keyd_fd, &cmd, sizeof(cmd));
262         read(keyd_fd, &cmd, sizeof(cmd));
263         if (cmd == KEYD_REPLY_OK) {
264                 write(keyd_fd, &keyid, sizeof(keyid));
265         }
266         
267         return 0;
268 }
269
270 /**
271  *      fetch_key_text - Trys to find the keys that contain the supplied text.
272  *      @search: The text to search for.
273  *      @publickey: A pointer to a structure to return the key in.
274  *
275  *      This function searches for the supplied text and returns the keys that
276  *      contain it.
277  */
278 int fetch_key_text(const char *search, struct openpgp_publickey **publickey)
279 {
280         struct buffer_ctx           keybuf;
281         struct openpgp_packet_list *packets = NULL;
282         int                         cmd = KEYD_CMD_GETTEXT;
283         ssize_t                     bytes = 0;
284         ssize_t                     count = 0;
285
286         write(keyd_fd, &cmd, sizeof(cmd));
287         read(keyd_fd, &cmd, sizeof(cmd));
288         if (cmd == KEYD_REPLY_OK) {
289                 bytes = strlen(search);
290                 write(keyd_fd, &bytes, sizeof(bytes));
291                 write(keyd_fd, search, bytes);
292                 keybuf.offset = 0;
293                 read(keyd_fd, &keybuf.size, sizeof(keybuf.size));
294                 if (keybuf.size > 0) {
295                         keybuf.buffer = malloc(keybuf.size);
296                         bytes = count = 0;
297                         logthing(LOGTHING_TRACE,
298                                         "Getting %d bytes of key data.",
299                                         keybuf.size);
300                         while (bytes >= 0 && count < keybuf.size) {
301                                 bytes = read(keyd_fd, &keybuf.buffer[count],
302                                                 keybuf.size - count);
303                                 logthing(LOGTHING_TRACE,
304                                                 "Read %d bytes.", bytes);
305                                 count += bytes;
306                         }
307                         read_openpgp_stream(buffer_fetchchar, &keybuf,
308                                         &packets, 0);
309                         parse_keys(packets, publickey);
310                         free_packet_list(packets);
311                         packets = NULL;
312                         free(keybuf.buffer);
313                         keybuf.buffer = NULL;
314                         keybuf.size = 0;
315                 }
316         }
317         
318         return (count > 0) ? 1 : 0;
319
320         return 0;
321 }
322
323 /**
324  *      getfullkeyid - Maps a 32bit key id to a 64bit one.
325  *      @keyid: The 32bit keyid.
326  *
327  *      This function maps a 32bit key id to the full 64bit one. It returns the
328  *      full keyid. If the key isn't found a keyid of 0 is returned.
329  */
330 uint64_t getfullkeyid(uint64_t keyid)
331 {
332         int cmd = KEYD_CMD_GETFULLKEYID;
333
334         write(keyd_fd, &cmd, sizeof(cmd));
335         read(keyd_fd, &cmd, sizeof(cmd));
336         if (cmd == KEYD_REPLY_OK) {
337                 write(keyd_fd, &keyid, sizeof(keyid));
338                 read(keyd_fd, &keyid, sizeof(keyid));
339         }
340
341         return keyid;
342 }
343
344 /**
345  *      dumpdb - dump the key database
346  *      @filenamebase: The base filename to use for the dump.
347  *
348  *      Dumps the database into one or more files, which contain pure OpenPGP
349  *      that can be reimported into onak or gpg. filenamebase provides a base
350  *      file name for the dump; several files may be created, all of which will
351  *      begin with this string and then have a unique number and a .pgp
352  *      extension.
353  */
354 int dumpdb(char *filenamebase)
355 {
356         return 0;
357 }
358
359 #define NEED_KEYID2UID 1
360 #define NEED_GETKEYSIGS 1
361 #include "keydb.c"