From: Jonathan McDowell <noodles@earth.li>
Date: Mon, 27 Sep 2004 22:22:25 +0000 (+0000)
Subject: Add key iteration functionality to keydb backends.
X-Git-Url: https://git.sommitrealweird.co.uk/onak.git/commitdiff_plain/f42ab5050f79833030453b21d69f4f3be9fcd0d0

Add key iteration functionality to keydb backends.
Add a function to the keydb backends which will call a given function
once for every contained in the db. Currently implemented for db4, keyd,
file and pg backends.
---

diff --git a/keyd.c b/keyd.c
index 7b6226e..f8f5d4a 100644
--- a/keyd.c
+++ b/keyd.c
@@ -19,12 +19,56 @@
 #include "cleanup.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"
 
+void iteratefunc(void *ctx, struct openpgp_publickey *key)
+{
+	struct openpgp_packet_list *packets = NULL;
+	struct openpgp_packet_list *list_end = NULL;
+	struct buffer_ctx           storebuf;
+	int                         ret = 0;
+	int                         fd = (int) ctx;
+
+	if (key != NULL) {
+		storebuf.offset = 0;
+		storebuf.size = 8192;
+		storebuf.buffer = malloc(8192);
+
+		logthing(LOGTHING_TRACE,
+				"Iterating over 0x%016llX.",
+				get_keyid(key));
+
+		flatten_publickey(key,
+				&packets,
+				&list_end);
+		write_openpgp_stream(buffer_putchar,
+				&storebuf,
+				packets);
+		logthing(LOGTHING_TRACE,
+				"Sending %d bytes.",
+				storebuf.offset);
+		ret = write(fd, &storebuf.offset,
+			sizeof(storebuf.offset));
+		if (ret != 0) {
+			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;
+	}
+
+	return;
+}
+
 int sock_init(const char *sockname)
 {
 	struct sockaddr_un sock;
@@ -236,6 +280,13 @@ int sock_do(int fd)
 				write(fd, &keyid, sizeof(keyid));
 			}
 			break;
+		case KEYD_CMD_KEYITER:
+			cmd = KEYD_REPLY_OK;
+			write(fd, &cmd, sizeof(cmd));
+			iterate_keys(iteratefunc, (void *) fd);
+			bytes = 0;
+			write(fd, &bytes, sizeof(bytes));
+			break;
 		case KEYD_CMD_CLOSE:
 			ret = 1;
 			break;
diff --git a/keyd.h b/keyd.h
index 7497cb4..3bc252a 100644
--- a/keyd.h
+++ b/keyd.h
@@ -19,6 +19,7 @@ enum keyd_ops {
 	KEYD_CMD_DELETE,
 	KEYD_CMD_GETTEXT,
 	KEYD_CMD_GETFULLKEYID,
+	KEYD_CMD_KEYITER,
 	KEYD_CMD_CLOSE,
 	KEYD_CMD_QUIT
 };
@@ -28,6 +29,6 @@ enum keyd_reply {
 	KEYD_REPLY_UNKNOWN_CMD = 1
 };
 
-static int keyd_version = 1;
+static int keyd_version = 2;
 
 #endif /* __KEYD_H__ */
diff --git a/keydb.h b/keydb.h
index b484831..ca2a823 100644
--- a/keydb.h
+++ b/keydb.h
@@ -159,4 +159,18 @@ uint64_t getfullkeyid(uint64_t keyid);
  */
 int dumpdb(char *filenamebase);
 
+/**
+ *	iterate_keys - call a function once for each key in the db.
+ *	@iterfunc: The function to call.
+ *	@ctx: A context pointer
+ *
+ *	Calls iterfunc once for each key in the database. ctx is passed
+ *	unaltered to iterfunc. This function is intended to aid database dumps
+ *	and statistic calculations.
+ *
+ *	Returns the number of keys we iterated over.
+ */
+int iterate_keys(void (*iterfunc)(void *ctx, struct openpgp_publickey *key),
+		void *ctx);
+
 #endif /* __KEYDB_H__ */
diff --git a/keydb_db2.c b/keydb_db2.c
index 020ee83..f9ca04b 100644
--- a/keydb_db2.c
+++ b/keydb_db2.c
@@ -3,7 +3,7 @@
  *
  * Jonathan McDowell <noodles@earth.li>
  *
- * Copyright 2002 Project Purple
+ * Copyright 2002-2004 Project Purple
  */
 
 #include <sys/types.h>
@@ -264,6 +264,22 @@ int dumpdb(char *filenamebase)
 	return 0;
 }
 
+/**
+ *	iterate_keys - call a function once for each key in the db.
+ *	@iterfunc: The function to call.
+ *	@ctx: A context pointer
+ *
+ *	Calls iterfunc once for each key in the database. ctx is passed
+ *	unaltered to iterfunc. This function is intended to aid database dumps
+ *	and statistic calculations.
+ *
+ *	Returns the number of keys we iterated over.
+ */
+int iterate_keys(void (*iterfunc)(void *ctx, struct openpgp_publickey *key),
+		void *ctx)
+{
+	return 0;
+}
 
 /*
  * Include the basic keydb routines.
diff --git a/keydb_db4.c b/keydb_db4.c
index 7f8e498..de2215c 100644
--- a/keydb_db4.c
+++ b/keydb_db4.c
@@ -978,6 +978,72 @@ int dumpdb(char *filenamebase)
 	return 0;
 }
 
+/**
+ *	iterate_keys - call a function once for each key in the db.
+ *	@iterfunc: The function to call.
+ *	@ctx: A context pointer
+ *
+ *	Calls iterfunc once for each key in the database. ctx is passed
+ *	unaltered to iterfunc. This function is intended to aid database dumps
+ *	and statistic calculations.
+ *
+ *	Returns the number of keys we iterated over.
+ */
+int iterate_keys(void (*iterfunc)(void *ctx, struct openpgp_publickey *key),
+		void *ctx)
+{
+	DBT                         dbkey, data;
+	DBC                        *cursor = NULL;
+	int                         ret = 0;
+	int                         i = 0;
+	int                         numkeys = 0;
+	struct buffer_ctx           fetchbuf;
+	struct openpgp_packet_list *packets = NULL;
+	struct openpgp_publickey   *key = NULL;
+
+	for (i = 0; i < numdbs; i++) {
+		ret = dbconns[i]->cursor(dbconns[i],
+			NULL,
+			&cursor,
+			0);   /* flags */
+
+		memset(&dbkey, 0, sizeof(dbkey));
+		memset(&data, 0, sizeof(data));
+		ret = cursor->c_get(cursor, &dbkey, &data, DB_NEXT);
+		while (ret == 0) {
+			fetchbuf.buffer = data.data;
+			fetchbuf.offset = 0;
+			fetchbuf.size = data.size;
+			read_openpgp_stream(buffer_fetchchar, &fetchbuf,
+				&packets, 0);
+			parse_keys(packets, &key);
+
+			iterfunc(ctx, key);
+			
+			free_publickey(key);
+			key = NULL;
+			free_packet_list(packets);
+			packets = NULL;
+			
+			memset(&dbkey, 0, sizeof(dbkey));
+			memset(&data, 0, sizeof(data));
+			ret = cursor->c_get(cursor, &dbkey, &data,
+					DB_NEXT);
+			numkeys++;
+		}
+		if (ret != DB_NOTFOUND) {
+			logthing(LOGTHING_ERROR,
+				"Problem reading key: %s",
+				db_strerror(ret));
+		}
+
+		ret = cursor->c_close(cursor);
+		cursor = NULL;
+	}
+	
+	return numkeys;
+}
+
 /**
  *	getfullkeyid - Maps a 32bit key id to a 64bit one.
  *	@keyid: The 32bit keyid.
diff --git a/keydb_file.c b/keydb_file.c
index 81cb22a..1ef81b4 100644
--- a/keydb_file.c
+++ b/keydb_file.c
@@ -3,11 +3,12 @@
  *
  * Jonathan McDowell <noodles@earth.li>
  *
- * Copyright 2002 Project Purple
+ * Copyright 2002-2004 Project Purple
  */
 
 #include <sys/types.h>
 #include <sys/uio.h>
+#include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
@@ -20,6 +21,7 @@
 #include "keyid.h"
 #include "keystructs.h"
 #include "ll.h"
+#include "log.h"
 #include "mem.h"
 #include "onak-conf.h"
 #include "parsekey.h"
@@ -167,6 +169,66 @@ int fetch_key_text(const char *search, struct openpgp_publickey **publickey)
 	return 0;
 }
 
+/**
+ *	iterate_keys - call a function once for each key in the db.
+ *	@iterfunc: The function to call.
+ *	@ctx: A context pointer
+ *
+ *	Calls iterfunc once for each key in the database. ctx is passed
+ *	unaltered to iterfunc. This function is intended to aid database dumps
+ *	and statistic calculations.
+ *
+ *	Returns the number of keys we iterated over.
+ */
+int iterate_keys(void (*iterfunc)(void *ctx, struct openpgp_publickey *key),
+		void *ctx)
+{
+	int                         numkeys = 0;
+	struct openpgp_packet_list *packets = NULL;
+	struct openpgp_publickey   *key = NULL;
+	DIR                        *dir;
+	char                        keyfile[1024];
+	int                         fd = -1;
+	struct dirent              *curfile = NULL;
+
+	dir = opendir(config.db_dir);
+
+	if (dir != NULL) {
+		while ((curfile = readdir(dir)) != NULL) {
+			if (curfile->d_name[0] == '0' &&
+					curfile->d_name[1] == 'x') {
+				snprintf(keyfile, 1023, "%s/%s",
+						config.db_dir,
+						curfile->d_name);
+				fd = open(keyfile, O_RDONLY);
+
+				if (fd > -1) {
+					read_openpgp_stream(file_fetchchar,
+							&fd,
+							&packets,
+							0);
+					parse_keys(packets, &key);
+
+					iterfunc(ctx, key);
+
+					free_publickey(key);
+					key = NULL;
+					free_packet_list(packets);
+					packets = NULL;
+					close(fd);
+				}
+				numkeys++;
+			}
+		}
+		
+		closedir(dir);
+		dir = NULL;
+	}
+
+	return numkeys;
+}
+
+
 /**
  *	dumpdb - dump the key database
  *	@filenamebase: The base filename to use for the dump.
diff --git a/keydb_fs.c b/keydb_fs.c
index 73d9758..1c5d14c 100644
--- a/keydb_fs.c
+++ b/keydb_fs.c
@@ -532,6 +532,23 @@ uint64_t getfullkeyid(uint64_t keyid)
 	return ret;
 }
 
+/**
+ *	iterate_keys - call a function once for each key in the db.
+ *	@iterfunc: The function to call.
+ *	@ctx: A context pointer
+ *
+ *	Calls iterfunc once for each key in the database. ctx is passed
+ *	unaltered to iterfunc. This function is intended to aid database dumps
+ *	and statistic calculations.
+ *
+ *	Returns the number of keys we iterated over.
+ */
+int iterate_keys(void (*iterfunc)(void *ctx, struct openpgp_publickey *key),
+		void *ctx)
+{
+	return 0;
+}
+
 /*
  * Include the basic keydb routines.
  */
diff --git a/keydb_keyd.c b/keydb_keyd.c
index 0399bc3..fac5548 100644
--- a/keydb_keyd.c
+++ b/keydb_keyd.c
@@ -356,6 +356,71 @@ int dumpdb(char *filenamebase)
 	return 0;
 }
 
+/**
+ *	iterate_keys - call a function once for each key in the db.
+ *	@iterfunc: The function to call.
+ *	@ctx: A context pointer
+ *
+ *	Calls iterfunc once for each key in the database. ctx is passed
+ *	unaltered to iterfunc. This function is intended to aid database dumps
+ *	and statistic calculations.
+ *
+ *	Returns the number of keys we iterated over.
+ */
+int iterate_keys(void (*iterfunc)(void *ctx, struct openpgp_publickey *key),
+		void *ctx)
+{
+	struct buffer_ctx           keybuf;
+	struct openpgp_packet_list *packets = NULL;
+	struct openpgp_publickey   *key = NULL;
+	int                         cmd = KEYD_CMD_KEYITER;
+	ssize_t                     bytes = 0;
+	ssize_t                     count = 0;
+	int                         numkeys = 0;
+
+	write(keyd_fd, &cmd, sizeof(cmd));
+	read(keyd_fd, &cmd, sizeof(cmd));
+	if (cmd == KEYD_REPLY_OK) {
+		keybuf.offset = 0;
+		read(keyd_fd, &keybuf.size, sizeof(keybuf.size));
+		while (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, &key);
+
+			if (iterfunc != NULL && key != NULL) {
+				iterfunc(ctx, key);
+			}
+
+			free_publickey(key);
+			key = NULL;
+			free_packet_list(packets);
+			packets = NULL;
+			free(keybuf.buffer);
+			keybuf.buffer = NULL;
+			keybuf.size = keybuf.offset = 0;
+
+			numkeys++;
+
+			read(keyd_fd, &keybuf.size, sizeof(keybuf.size));
+		}
+	}
+	
+	return numkeys;
+}
+
 #define NEED_KEYID2UID 1
 #define NEED_GETKEYSIGS 1
 #define NEED_UPDATEKEYS 1
diff --git a/keydb_pg.c b/keydb_pg.c
index 88682af..afdbb23 100644
--- a/keydb_pg.c
+++ b/keydb_pg.c
@@ -3,7 +3,7 @@
  *
  * Jonathan McDowell <noodles@earth.li>
  *
- * Copyright 2002 Project Purple
+ * Copyright 2002-2004 Project Purple
  */
 
 #include <postgresql/libpq-fe.h>
@@ -582,6 +582,65 @@ int dumpdb(char *filenamebase)
 	return 0;
 }
 
+/**
+ *	iterate_keys - call a function once for each key in the db.
+ *	@iterfunc: The function to call.
+ *	@ctx: A context pointer
+ *
+ *	Calls iterfunc once for each key in the database. ctx is passed
+ *	unaltered to iterfunc. This function is intended to aid database dumps
+ *	and statistic calculations.
+ *
+ *	Returns the number of keys we iterated over.
+ */
+int iterate_keys(void (*iterfunc)(void *ctx, struct openpgp_publickey *key),
+		void *ctx)
+{
+	struct openpgp_packet_list *packets = NULL;
+	struct openpgp_publickey *key = NULL;
+	PGresult *result = NULL;
+	char *oids = NULL;
+	char statement[1024];
+	int fd = -1;
+	int i = 0;
+	int numkeys = 0;
+	Oid key_oid;
+
+	result = PQexec(dbconn, "SELECT keydata FROM onak_keys;");
+
+	if (PQresultStatus(result) == PGRES_TUPLES_OK) {
+		numkeys = PQntuples(result);
+		for (i = 0; i < numkeys; i++) {
+			oids = PQgetvalue(result, i, 0);
+			key_oid = (Oid) atoi(oids);
+
+			fd = lo_open(dbconn, key_oid, INV_READ);
+			if (fd < 0) {
+				logthing(LOGTHING_ERROR,
+						"Can't open large object.");
+			} else {
+				read_openpgp_stream(keydb_fetchchar, &fd,
+						&packets, 0);
+				parse_keys(packets, key);
+				lo_close(dbconn, fd);
+
+				iterfunc(ctx, key);
+					
+				free_publickey(key);
+				key = NULL;
+				free_packet_list(packets);
+				packets = NULL;
+			}
+		}
+	} else if (PQresultStatus(result) != PGRES_TUPLES_OK) {
+		logthing(LOGTHING_ERROR, "Problem retrieving key from DB.");
+	}
+
+	PQclear(result);
+
+	return (numkeys);
+}
+
 /*
  * Include the basic keydb routines.
  */