From: Jonathan McDowell Date: Sat, 25 Sep 2004 09:34:55 +0000 (+0000) Subject: Add keyd backend (persistant database access over Unix socket) X-Git-Url: https://git.sommitrealweird.co.uk/onak.git/commitdiff_plain/66748d60571a5ebbbc0f0cb84c061f9c62f5aef7?hp=848a41ea337ecee39f3eaf9d091a316d07ec8e9d Add keyd backend (persistant database access over Unix socket) 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. --- diff --git a/Makefile.in b/Makefile.in index 334ec29..cd6620e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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 diff --git a/configure.ac b/configure.ac index 1b9e633..7b6bce6 100644 --- a/configure.ac +++ b/configure.ac @@ -9,6 +9,8 @@ AC_C_BIGENDIAN AC_ARG_ENABLE(backend,AC_HELP_STRING([--enable-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 index 0000000..7b6226e --- /dev/null +++ b/keyd.c @@ -0,0 +1,317 @@ +/* + * keyd.c - key retrieval daemon + * + * Jonathan McDowell + * + * Copyright 2004 Project Purple + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 index 0000000..7497cb4 --- /dev/null +++ b/keyd.h @@ -0,0 +1,33 @@ +/* + * keyd.h - Public API for keyd. + * + * Jonathan McDowell + * + * 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 index 0000000..10716ee --- /dev/null +++ b/keydb_keyd.c @@ -0,0 +1,361 @@ +/* + * keydb_keyd.c - Routines to talk to keyd backend. + * + * Jonathan McDowell + * + * Copyright 2004 Project Purple + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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"