]> the.earth.li Git - onak.git/commitdiff
Add keyd backend (persistant database access over Unix socket)
authorJonathan McDowell <noodles@earth.li>
Sat, 25 Sep 2004 09:34:55 +0000 (09:34 +0000)
committerJonathan McDowell <noodles@earth.li>
Sat, 25 Sep 2004 09:34:55 +0000 (09:34 +0000)
Add keyd, which runs in the background and talks to the real database
and then communicates with the various onak programs over a Unix
socket.

Makefile.in
configure.ac
keyd.c [new file with mode: 0644]
keyd.h [new file with mode: 0644]
keydb_keyd.c [new file with mode: 0644]

index 334ec2923b6bb7d740af3db26115f66089d30d3d..cd6620ef24d8e38b91e3eee014bd2c7719938dc2 100644 (file)
@@ -16,19 +16,32 @@ prefix ?= @prefix@
 exec_prefix ?= @exec_prefix@
 
 PROGS = add lookup gpgwww onak splitkeys onak-mail.pl stripkey
-CORE_OBJS = armor.o charfuncs.o decodekey.o getcgi.o hash.o keydb_$(DBTYPE).o \
+CORE_OBJS = armor.o charfuncs.o decodekey.o getcgi.o hash.o \
        keyid.o keyindex.o ll.o mem.o onak-conf.o parsekey.o sha1.o md5.o \
        log.o photoid.o wordlist.o cleanup.o
-OBJS = merge.o stats.o sendsync.o cleankey.o $(CORE_OBJS)
 SRCS = armor.c parsekey.c merge.c keyid.c md5.c sha1.c main.c getcgi.c mem.c \
        keyindex.c stats.c lookup.c add.c keydb_$(DBTYPE).c ll.c hash.c \
        gpgwww.c onak-conf.c charfuncs.c sendsync.c log.c photoid.c \
        wordlist.c cleankey.c cleanup.c
 
+ifeq (x@KEYD@, xyes)
+PROGS += keyd
+KEYDB_OBJ = keydb_keyd.o
+SRCS += keyd.c keydb_keyd.c
+else
+KEYDB_OBJ = keydb_$(DBTYPE).o
+endif
+
+OBJS = merge.o stats.o sendsync.o cleankey.o $(CORE_OBJS) $(KEYDB_OBJ)
+
 all: .depend $(PROGS) testparse maxpath sixdegrees splitkeys onak.conf
 
-splitkeys: splitkeys.o $(CORE_OBJS)
-       $(CC) $(LDFLAGS) -o splitkeys splitkeys.o $(CORE_OBJS) $(LIBS)
+keyd: keyd.o $(CORE_OBJS) keydb_$(DBTYPE).o
+       $(CC) $(LDFLAGS) -o keyd keyd.o $(CORE_OBJS) keydb_$(DBTYPE).o $(LIBS)
+
+splitkeys: splitkeys.o $(CORE_OBJS) $(KEYDB_OBJ)
+       $(CC) $(LDFLAGS) -o splitkeys splitkeys.o $(CORE_OBJS) $(KEYDB_OBJ) \
+               $(LIBS)
 
 testparse: main.o $(OBJS)
        $(CC) $(LDFLAGS) -o testparse main.o $(OBJS) $(LIBS)
@@ -45,17 +58,17 @@ stripkey: stripkey.o $(OBJS)
 gpgwww: gpgwww.o $(OBJS)
        $(CC) $(LDFLAGS) -o gpgwww gpgwww.o $(OBJS) $(LIBS)
 
-lookup: lookup.o cleankey.o merge.o $(CORE_OBJS)
+lookup: lookup.o cleankey.o merge.o $(CORE_OBJS) $(KEYDB_OBJ)
        $(CC) $(LDFLAGS) -o lookup lookup.o cleankey.o merge.o $(CORE_OBJS) \
-               $(LIBS)
+               $(KEYDB_OBJ) $(LIBS)
 
-add: add.o cleankey.o merge.o sendsync.o $(CORE_OBJS)
+add: add.o cleankey.o merge.o sendsync.o $(CORE_OBJS) $(KEYDB_OBJ)
        $(CC) $(LDFLAGS) -o add add.o cleankey.o merge.o sendsync.o \
-               $(CORE_OBJS) $(LIBS)
+               $(CORE_OBJS) $(KEYDB_OBJ) $(LIBS)
 
-onak: onak.o merge.o cleankey.o $(CORE_OBJS)
+onak: onak.o merge.o cleankey.o $(CORE_OBJS) $(KEYDB_OBJ)
        $(CC) $(LDFLAGS) -o onak onak.o merge.o cleankey.o \
-               $(CORE_OBJS) $(LIBS)
+               $(CORE_OBJS) $(KEYDB_OBJ) $(LIBS)
 
 onak-conf.o: onak-conf.c onak-conf.h
        $(CC) $(CFLAGS) -DCONFIGFILE=\"@sysconfdir@/onak.conf\" -c onak-conf.c
index 1b9e63346e485bfca739baf6be9e25a5fe2f8521..7b6bce65ee52496a1007a8ff326fbe5f22d67ac4 100644 (file)
@@ -9,6 +9,8 @@ AC_C_BIGENDIAN
 
 AC_ARG_ENABLE(backend,AC_HELP_STRING([--enable-backend=<backend>],[Choose the backend database to use. Defaults to db4.]), [], [enable_backend="db4"])
 
+AC_ARG_ENABLE(keyd,AC_HELP_STRING([--enable-keyd],[Use keyd as the DB backend.]), [], [])
+
 AC_MSG_CHECKING([which key database backend to use])
 AC_MSG_RESULT([$enable_backend])
 AC_CHECK_FILE([$srcdir/keydb_$enable_backend.c], ,AC_MSG_ERROR([non existent key database backend $enable_backend]))
@@ -46,6 +48,8 @@ fi
 
 AC_SUBST(DBTYPE, $enable_backend)
 
+AC_SUBST(KEYD, $enable_keyd)
+
 AC_CONFIG_FILES(Makefile)
 
 AC_OUTPUT
diff --git a/keyd.c b/keyd.c
new file mode 100644 (file)
index 0000000..7b6226e
--- /dev/null
+++ b/keyd.c
@@ -0,0 +1,317 @@
+/*
+ * keyd.c - key retrieval daemon
+ *
+ * Jonathan McDowell <noodles@earth.li>
+ * 
+ * Copyright 2004 Project Purple
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "charfuncs.h"
+#include "cleanup.h"
+#include "keyd.h"
+#include "keydb.h"
+#include "keystructs.h"
+#include "log.h"
+#include "mem.h"
+#include "onak-conf.h"
+#include "parsekey.h"
+
+int sock_init(const char *sockname)
+{
+       struct sockaddr_un sock;
+       int                fd = -1;
+       int                ret = -1;
+
+       fd = socket(PF_UNIX, SOCK_STREAM, 0);
+       if (fd != -1) {
+               ret = fcntl(fd, F_SETFD, 1);
+       }
+
+       if (ret != -1) {
+               sock.sun_family = AF_UNIX;
+               strncpy(sock.sun_path, sockname, sizeof(sock.sun_path) - 1);
+               unlink(sockname);
+               ret = bind(fd, (struct sockaddr *) &sock, sizeof(sock));
+       }
+
+       if (ret != -1) {
+               ret = listen(fd, 5);
+       }
+       
+       return fd;
+}
+
+int sock_do(int fd)
+{
+       int      cmd = KEYD_CMD_UNKNOWN;
+       ssize_t  bytes = 0;
+       ssize_t  count = 0;
+       int      ret = 0;
+       uint64_t keyid = 0;
+       char     *search = NULL;
+       struct openpgp_publickey *key = NULL;
+       struct openpgp_packet_list *packets = NULL;
+       struct openpgp_packet_list *list_end = NULL;
+       struct buffer_ctx storebuf;
+
+       /*
+        * Get the command from the client.
+        */
+       bytes = read(fd, &cmd, sizeof(cmd));
+
+       logthing(LOGTHING_DEBUG, "Read %d bytes, command: %d", bytes, cmd);
+
+       if (bytes != sizeof(cmd)) {
+               ret = 1;
+       }
+       
+       if (ret == 0) {
+               switch (cmd) {
+               case KEYD_CMD_VERSION:
+                       cmd = KEYD_REPLY_OK;
+                       write(fd, &cmd, sizeof(cmd));
+                       write(fd, &keyd_version, sizeof(keyd_version));
+                       break;
+               case KEYD_CMD_GET:
+                       cmd = KEYD_REPLY_OK;
+                       write(fd, &cmd, sizeof(cmd));
+                       bytes = read(fd, &keyid, sizeof(keyid));
+                       if (bytes != sizeof(keyid)) {
+                               ret = 1;
+                       }
+                       storebuf.offset = 0;
+                       if (ret == 0) {
+                               logthing(LOGTHING_INFO,
+                                               "Fetching 0x%llX, result: %d",
+                                               keyid,
+                                               fetch_key(keyid, &key, false));
+                               if (key != NULL) {
+                                       storebuf.size = 8192;
+                                       storebuf.buffer = malloc(8192);
+
+                                       flatten_publickey(key,
+                                                       &packets,
+                                                       &list_end);
+                                       write_openpgp_stream(buffer_putchar,
+                                                       &storebuf,
+                                                       packets);
+                                       logthing(LOGTHING_TRACE,
+                                                       "Sending %d bytes.",
+                                                       storebuf.offset);
+                                       write(fd, &storebuf.offset,
+                                               sizeof(storebuf.offset));
+                                       write(fd, storebuf.buffer,
+                                               storebuf.offset);
+
+                                       free(storebuf.buffer);
+                                       storebuf.buffer = NULL;
+                                       storebuf.size = storebuf.offset = 0;
+                                       free_packet_list(packets);
+                                       packets = list_end = NULL;
+                                       free_publickey(key);
+                                       key = NULL;
+                               } else {
+                                       write(fd, &storebuf.offset,
+                                               sizeof(storebuf.offset));
+                               }
+                       }
+                       break;
+               case KEYD_CMD_GETTEXT:
+                       cmd = KEYD_REPLY_OK;
+                       write(fd, &cmd, sizeof(cmd));
+                       bytes = read(fd, &count, sizeof(count));
+                       if (bytes != sizeof(count)) {
+                               ret = 1;
+                       }
+                       storebuf.offset = 0;
+                       if (ret == 0) {
+                               search = malloc(count+1);
+                               read(fd, search, count);
+                               search[count] = 0;
+                               logthing(LOGTHING_INFO,
+                                               "Fetching %s, result: %d",
+                                               search,
+                                               fetch_key_text(search, &key));
+                               if (key != NULL) {
+                                       storebuf.size = 8192;
+                                       storebuf.buffer = malloc(8192);
+
+                                       flatten_publickey(key,
+                                                       &packets,
+                                                       &list_end);
+                                       write_openpgp_stream(buffer_putchar,
+                                                       &storebuf,
+                                                       packets);
+                                       logthing(LOGTHING_TRACE,
+                                                       "Sending %d bytes.",
+                                                       storebuf.offset);
+                                       write(fd, &storebuf.offset,
+                                               sizeof(storebuf.offset));
+                                       write(fd, storebuf.buffer,
+                                               storebuf.offset);
+
+                                       free(storebuf.buffer);
+                                       storebuf.buffer = NULL;
+                                       storebuf.size = storebuf.offset = 0;
+                                       free_packet_list(packets);
+                                       packets = list_end = NULL;
+                                       free_publickey(key);
+                                       key = NULL;
+                               } else {
+                                       write(fd, &storebuf.offset,
+                                               sizeof(storebuf.offset));
+                               }
+                       }
+                       break;
+               case KEYD_CMD_STORE:
+                       cmd = KEYD_REPLY_OK;
+                       write(fd, &cmd, sizeof(cmd));
+                       storebuf.offset = 0;
+                       bytes = read(fd, &storebuf.size,
+                                       sizeof(storebuf.size));
+                       logthing(LOGTHING_TRACE, "Reading %d bytes.",
+                                       storebuf.size);
+                       if (bytes != sizeof(storebuf.size)) {
+                               ret = 1;
+                       }
+                       if (ret == 0 && storebuf.size > 0) {
+                               storebuf.buffer = malloc(storebuf.size);
+                               bytes = count = 0;
+                               while (bytes >= 0 && count < storebuf.size) {
+                                       bytes = read(fd,
+                                               &storebuf.buffer[count],
+                                               storebuf.size - count);
+                                       logthing(LOGTHING_TRACE,
+                                                       "Read %d bytes.",
+                                                       bytes);
+                                       count += bytes;
+                               }
+                               read_openpgp_stream(buffer_fetchchar,
+                                               &storebuf,
+                                               &packets,
+                                               0);
+                               parse_keys(packets, &key);
+                               store_key(key, false, false);
+                               free_packet_list(packets);
+                               packets = NULL;
+                               free_publickey(key);
+                               key = NULL;
+                               free(storebuf.buffer);
+                               storebuf.buffer = NULL;
+                               storebuf.size = storebuf.offset = 0;
+                       }
+                       break;
+               case KEYD_CMD_DELETE:
+                       cmd = KEYD_REPLY_OK;
+                       write(fd, &cmd, sizeof(cmd));
+                       bytes = read(fd, &keyid, sizeof(keyid));
+                       if (bytes != sizeof(keyid)) {
+                               ret = 1;
+                       }
+                       if (ret == 0) {
+                               logthing(LOGTHING_INFO,
+                                               "Deleting 0x%llX, result: %d",
+                                               keyid,
+                                               delete_key(keyid, false));
+                       }
+                       break;
+               case KEYD_CMD_GETFULLKEYID:
+                       cmd = KEYD_REPLY_OK;
+                       write(fd, &cmd, sizeof(cmd));
+                       bytes = read(fd, &keyid, sizeof(keyid));
+                       if (bytes != sizeof(keyid)) {
+                               ret = 1;
+                       }
+                       if (ret == 0) {
+                               keyid = getfullkeyid(keyid);
+                               write(fd, &keyid, sizeof(keyid));
+                       }
+                       break;
+               case KEYD_CMD_CLOSE:
+                       ret = 1;
+                       break;
+               case KEYD_CMD_QUIT:
+                       trytocleanup();
+                       break;
+               default:
+                       logthing(LOGTHING_ERROR, "Got unknown command: %d",
+                                       cmd);
+                       cmd = KEYD_REPLY_UNKNOWN_CMD;
+                       write(fd, &cmd, sizeof(cmd));
+               }
+       }
+
+       return(ret);
+}
+
+int sock_close(int fd)
+{
+       return shutdown(fd, SHUT_RDWR);
+}
+
+int sock_accept(int fd)
+{
+       struct sockaddr_un sock;
+       socklen_t          socklen;
+       int    srv = -1;
+       int    ret = -1;
+
+       socklen = sizeof(sock);
+       srv = accept(fd, (struct sockaddr *) &sock, &socklen);
+       if (srv != -1) {
+               ret = fcntl(srv, F_SETFD, 1);
+       }
+
+       if (ret != -1) {
+               while (!sock_do(srv)) ;
+               sock_close(srv);
+       }
+
+       return 1;
+}
+
+int main(int argc, char *argv[])
+{
+       int fd = -1;
+       fd_set rfds;
+       char sockname[1024];
+
+       readconfig(NULL);
+       initlogthing("keyd", config.logfile);
+
+       catchsignals();
+       
+       snprintf(sockname, 1023, "%s/%s", config.db_dir, KEYD_SOCKET);
+       fd = sock_init(sockname);
+
+       if (fd != -1) {
+               FD_ZERO(&rfds);
+               FD_SET(fd, &rfds);
+
+               initdb(false);
+
+               logthing(LOGTHING_NOTICE, "Accepting connections.");
+               while (!cleanup() && select(fd + 1, &rfds, NULL, NULL, NULL) != -1) {
+                       logthing(LOGTHING_INFO, "Accepted connection.");
+                       sock_accept(fd);
+                       FD_SET(fd, &rfds);
+               }
+               cleanupdb();
+               sock_close(fd);
+               unlink(sockname);
+       }
+
+       cleanuplogthing();
+       cleanupconfig();
+       
+       return(EXIT_SUCCESS);
+}
diff --git a/keyd.h b/keyd.h
new file mode 100644 (file)
index 0000000..7497cb4
--- /dev/null
+++ b/keyd.h
@@ -0,0 +1,33 @@
+/*
+ * keyd.h - Public API for keyd.
+ *
+ * Jonathan McDowell <noodles@earth.li>
+ *
+ * Copyright 2004 Project Purple
+ */
+
+#ifndef __KEYD_H__
+#define __KEYD_H__
+
+#define KEYD_SOCKET "keyd.sock"
+
+enum keyd_ops {
+       KEYD_CMD_UNKNOWN = 0,
+       KEYD_CMD_VERSION = 1,
+       KEYD_CMD_GET,
+       KEYD_CMD_STORE,
+       KEYD_CMD_DELETE,
+       KEYD_CMD_GETTEXT,
+       KEYD_CMD_GETFULLKEYID,
+       KEYD_CMD_CLOSE,
+       KEYD_CMD_QUIT
+};
+
+enum keyd_reply {
+       KEYD_REPLY_OK = 0,
+       KEYD_REPLY_UNKNOWN_CMD = 1
+};
+
+static int keyd_version = 1;
+
+#endif /* __KEYD_H__ */
diff --git a/keydb_keyd.c b/keydb_keyd.c
new file mode 100644 (file)
index 0000000..10716ee
--- /dev/null
@@ -0,0 +1,361 @@
+/*
+ * keydb_keyd.c - Routines to talk to keyd backend.
+ *
+ * Jonathan McDowell <noodles@earth.li>
+ *
+ * Copyright 2004 Project Purple
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "charfuncs.h"
+#include "keyd.h"
+#include "keydb.h"
+#include "keyid.h"
+#include "keystructs.h"
+#include "log.h"
+#include "mem.h"
+#include "onak-conf.h"
+#include "parsekey.h"
+
+/**
+ *     keyd_fd - our file descriptor for the socket connection to keyd.
+ */
+static int keyd_fd = -1;
+
+/**
+ *     initdb - Initialize the key database.
+ *     @readonly: If we'll only be reading the DB, not writing to it.
+ *
+ *     This function should be called before any of the other functions in
+ *     this file are called in order to allow the DB to be initialized ready
+ *     for access.
+ */
+void initdb(bool readonly)
+{
+       struct sockaddr_un sock;
+       int                cmd = KEYD_CMD_UNKNOWN;
+       int                reply = KEYD_REPLY_UNKNOWN_CMD;
+       ssize_t            count;
+
+       keyd_fd = socket(PF_UNIX, SOCK_STREAM, 0);
+       if (keyd_fd < 0) {
+               logthing(LOGTHING_CRITICAL,
+                               "Couldn't open socket: %s (%d)",
+                               strerror(errno),
+                               errno);
+               exit(EXIT_FAILURE);
+       }
+
+       sock.sun_family = AF_UNIX;
+       snprintf(sock.sun_path, sizeof(sock.sun_path) - 1, "%s/%s",
+                       config.db_dir,
+                       KEYD_SOCKET);
+       if (connect(keyd_fd, (struct sockaddr *) &sock, sizeof(sock)) < 0) {
+               logthing(LOGTHING_CRITICAL,
+                               "Couldn't connect to socket %s: %s (%d)",
+                               sock.sun_path,
+                               strerror(errno),
+                               errno);
+               exit(EXIT_FAILURE);
+       }
+
+       cmd = KEYD_CMD_VERSION;
+       if (write(keyd_fd, &cmd, sizeof(cmd)) != sizeof(cmd)) {
+               logthing(LOGTHING_CRITICAL,
+                               "Couldn't write version cmd: %s (%d)",
+                               strerror(errno),
+                               errno);
+       } else {
+               count = read(keyd_fd, &reply, sizeof(reply));
+               if (count == sizeof(reply)) {
+                       if (reply == KEYD_REPLY_OK) {
+                               count = read(keyd_fd, &reply, sizeof(reply));
+                               logthing(LOGTHING_DEBUG,
+                                               "keyd protocol version %d",
+                                               reply);
+                               if (reply != keyd_version) {
+                                       logthing(LOGTHING_CRITICAL,
+                                               "Error! keyd protocol version "
+                                               "mismatch. (us = %d, it = %d)",
+                                               keyd_version, reply);
+                               }
+                       }
+               }
+       }
+
+       return;
+}
+
+/**
+ *     cleanupdb - De-initialize the key database.
+ *
+ *     This function should be called upon program exit to allow the DB to
+ *     cleanup after itself.
+ */
+void cleanupdb(void)
+{
+       if (shutdown(keyd_fd, SHUT_RDWR) < 0) {
+               logthing(LOGTHING_NOTICE, "Error shutting down socket: %d",
+                               errno);
+       }
+       keyd_fd = -1;
+
+       return;
+}
+
+
+/**
+ *     starttrans - Start a transaction.
+ *
+ *     Start a transaction. Intended to be used if we're about to perform many
+ *     operations on the database to help speed it all up, or if we want
+ *     something to only succeed if all relevant operations are successful.
+ */
+bool starttrans(void)
+{
+       return true;
+}
+
+/**
+ *     endtrans - End a transaction.
+ *
+ *     Ends a transaction.
+ */
+void endtrans(void)
+{
+       return;
+}
+
+/**
+ *     fetch_key - Given a keyid fetch the key from storage.
+ *     @keyid: The keyid to fetch.
+ *     @publickey: A pointer to a structure to return the key in.
+ *     @intrans: If we're already in a transaction.
+ *
+ *     This function returns a public key from whatever storage mechanism we
+ *     are using.
+ *
+ *      TODO: What about keyid collisions? Should we use fingerprint instead?
+ */
+int fetch_key(uint64_t keyid, struct openpgp_publickey **publickey,
+               bool intrans)
+{
+       struct buffer_ctx           keybuf;
+       struct openpgp_packet_list *packets = NULL;
+       int                         cmd = KEYD_CMD_GET;
+       ssize_t                     bytes = 0;
+       ssize_t                     count = 0;
+
+       write(keyd_fd, &cmd, sizeof(cmd));
+       read(keyd_fd, &cmd, sizeof(cmd));
+       if (cmd == KEYD_REPLY_OK) {
+               write(keyd_fd, &keyid, sizeof(keyid));
+               keybuf.offset = 0;
+               read(keyd_fd, &keybuf.size, sizeof(keybuf.size));
+               if (keybuf.size > 0) {
+                       keybuf.buffer = malloc(keybuf.size);
+                       bytes = count = 0;
+                       logthing(LOGTHING_TRACE,
+                                       "Getting %d bytes of key data.",
+                                       keybuf.size);
+                       while (bytes >= 0 && count < keybuf.size) {
+                               bytes = read(keyd_fd, &keybuf.buffer[count],
+                                               keybuf.size - count);
+                               logthing(LOGTHING_TRACE,
+                                               "Read %d bytes.", bytes);
+                               count += bytes;
+                       }
+                       read_openpgp_stream(buffer_fetchchar, &keybuf,
+                                       &packets, 0);
+                       parse_keys(packets, publickey);
+                       free_packet_list(packets);
+                       packets = NULL;
+                       free(keybuf.buffer);
+                       keybuf.buffer = NULL;
+                       keybuf.size = 0;
+               }
+       }
+       
+       return (count > 0) ? 1 : 0;
+}
+
+/**
+ *     store_key - Takes a key and stores it.
+ *     @publickey: A pointer to the public key to store.
+ *     @intrans: If we're already in a transaction.
+ *     @update: If true the key exists and should be updated.
+ *
+ *     This function stores a public key in whatever storage mechanism we are
+ *     using. intrans indicates if we're already in a transaction so don't
+ *     need to start one. update indicates if the key already exists and is
+ *     just being updated.
+ *
+ *     TODO: Do we store multiple keys of the same id? Or only one and replace
+ *     it?
+ */
+int store_key(struct openpgp_publickey *publickey, bool intrans, bool update)
+{
+       struct buffer_ctx           keybuf;
+       struct openpgp_packet_list *packets = NULL;
+       struct openpgp_packet_list *list_end = NULL;
+       struct openpgp_publickey   *next = NULL;
+       int                         cmd = KEYD_CMD_STORE;
+       uint64_t                    keyid;
+
+       keyid = get_keyid(publickey);
+       
+       if (update) {
+               delete_key(keyid, false);
+       }
+
+       write(keyd_fd, &cmd, sizeof(cmd));
+       read(keyd_fd, &cmd, sizeof(cmd));
+       if (cmd == KEYD_REPLY_OK) {
+               keybuf.offset = 0;
+               keybuf.size = 8192;
+               keybuf.buffer = malloc(keybuf.size);
+
+               next = publickey->next;
+               publickey->next = NULL;
+               flatten_publickey(publickey,
+                               &packets,
+                               &list_end);
+               publickey->next = next;
+
+               write_openpgp_stream(buffer_putchar, &keybuf, packets);
+               logthing(LOGTHING_TRACE, "Sending %d bytes.", keybuf.offset);
+               write(keyd_fd, &keybuf.offset, sizeof(keybuf.offset));
+               write(keyd_fd, keybuf.buffer, keybuf.offset);
+
+               free_packet_list(packets);
+               packets = list_end = NULL;
+               free(keybuf.buffer);
+               keybuf.buffer = NULL;
+               keybuf.size = keybuf.offset = 0;
+       }
+       
+       return 0;
+}
+
+/**
+ *     delete_key - Given a keyid delete the key from storage.
+ *     @keyid: The keyid to delete.
+ *     @intrans: If we're already in a transaction.
+ *
+ *     This function deletes a public key from whatever storage mechanism we
+ *     are using. Returns 0 if the key existed.
+ */
+int delete_key(uint64_t keyid, bool intrans)
+{
+       int cmd = KEYD_CMD_DELETE;
+
+       write(keyd_fd, &cmd, sizeof(cmd));
+       read(keyd_fd, &cmd, sizeof(cmd));
+       if (cmd == KEYD_REPLY_OK) {
+               write(keyd_fd, &keyid, sizeof(keyid));
+       }
+       
+       return 0;
+}
+
+/**
+ *     fetch_key_text - Trys to find the keys that contain the supplied text.
+ *     @search: The text to search for.
+ *     @publickey: A pointer to a structure to return the key in.
+ *
+ *     This function searches for the supplied text and returns the keys that
+ *     contain it.
+ */
+int fetch_key_text(const char *search, struct openpgp_publickey **publickey)
+{
+       struct buffer_ctx           keybuf;
+       struct openpgp_packet_list *packets = NULL;
+       int                         cmd = KEYD_CMD_GETTEXT;
+       ssize_t                     bytes = 0;
+       ssize_t                     count = 0;
+
+       write(keyd_fd, &cmd, sizeof(cmd));
+       read(keyd_fd, &cmd, sizeof(cmd));
+       if (cmd == KEYD_REPLY_OK) {
+               bytes = strlen(search);
+               write(keyd_fd, &bytes, sizeof(bytes));
+               write(keyd_fd, search, bytes);
+               keybuf.offset = 0;
+               read(keyd_fd, &keybuf.size, sizeof(keybuf.size));
+               if (keybuf.size > 0) {
+                       keybuf.buffer = malloc(keybuf.size);
+                       bytes = count = 0;
+                       logthing(LOGTHING_TRACE,
+                                       "Getting %d bytes of key data.",
+                                       keybuf.size);
+                       while (bytes >= 0 && count < keybuf.size) {
+                               bytes = read(keyd_fd, &keybuf.buffer[count],
+                                               keybuf.size - count);
+                               logthing(LOGTHING_TRACE,
+                                               "Read %d bytes.", bytes);
+                               count += bytes;
+                       }
+                       read_openpgp_stream(buffer_fetchchar, &keybuf,
+                                       &packets, 0);
+                       parse_keys(packets, publickey);
+                       free_packet_list(packets);
+                       packets = NULL;
+                       free(keybuf.buffer);
+                       keybuf.buffer = NULL;
+                       keybuf.size = 0;
+               }
+       }
+       
+       return (count > 0) ? 1 : 0;
+
+       return 0;
+}
+
+/**
+ *     getfullkeyid - Maps a 32bit key id to a 64bit one.
+ *     @keyid: The 32bit keyid.
+ *
+ *     This function maps a 32bit key id to the full 64bit one. It returns the
+ *     full keyid. If the key isn't found a keyid of 0 is returned.
+ */
+uint64_t getfullkeyid(uint64_t keyid)
+{
+       int cmd = KEYD_CMD_GETFULLKEYID;
+
+       write(keyd_fd, &cmd, sizeof(cmd));
+       read(keyd_fd, &cmd, sizeof(cmd));
+       if (cmd == KEYD_REPLY_OK) {
+               write(keyd_fd, &keyid, sizeof(keyid));
+               read(keyd_fd, &keyid, sizeof(keyid));
+       }
+
+       return keyid;
+}
+
+/**
+ *     dumpdb - dump the key database
+ *     @filenamebase: The base filename to use for the dump.
+ *
+ *     Dumps the database into one or more files, which contain pure OpenPGP
+ *     that can be reimported into onak or gpg. filenamebase provides a base
+ *     file name for the dump; several files may be created, all of which will
+ *     begin with this string and then have a unique number and a .pgp
+ *     extension.
+ */
+int dumpdb(char *filenamebase)
+{
+       return 0;
+}
+
+#define NEED_KEYID2UID 1
+#define NEED_GETKEYSIGS 1
+#include "keydb.c"