From 5d25774c5cd9f80709f852f79bce26d582fad360 Mon Sep 17 00:00:00 2001 From: Jonathan McDowell Date: Sun, 24 Apr 2011 21:49:32 -0700 Subject: [PATCH] Add /pks/hashquery Add /pks/hashquery - an implementation of the SKS hash retrieval portion of the gossip protocol. hashquery takes a marshalled array of SKS hashes to retrieve and returns a marshalled array of the keys requested. (The marshalling functions essentially take the hash/key structures and flatten them to a byte stream with a preceding network order 32 bit size value.) --- .bzrignore | 1 + Makefile.in | 10 ++- debian/changelog | 6 ++ hashquery.c | 113 +++++++++++++++++++++++++++++++++ marshal.c | 159 +++++++++++++++++++++++++++++++++++++++++++++++ marshal.h | 137 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 423 insertions(+), 3 deletions(-) create mode 100644 hashquery.c create mode 100644 marshal.c create mode 100644 marshal.h diff --git a/.bzrignore b/.bzrignore index d6678de..2083983 100644 --- a/.bzrignore +++ b/.bzrignore @@ -5,6 +5,7 @@ config.log config.h config.h.in add +hashquery lookup onak gpgwww diff --git a/Makefile.in b/Makefile.in index 867245d..1fb16d9 100644 --- a/Makefile.in +++ b/Makefile.in @@ -16,14 +16,14 @@ MAKEDEPEND = $(CC) -MM 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 \ +PROGS = add lookup hashquery gpgwww onak splitkeys onak-mail.pl stripkey +CORE_OBJS = armor.o charfuncs.o decodekey.o getcgi.o hash.o marshal.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 merge.o sendsync.o keyarray.o 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 keyarray.c \ + wordlist.c cleankey.c cleanup.c keyarray.c hashquery.c marshal.c \ $(foreach be,@BACKENDS@,keydb_$(be).c) PROGS_LDFLAGS_EXTRA = @@ -110,6 +110,10 @@ gpgwww: gpgwww.o $(OBJS) $(CC) $(LDFLAGS) -o gpgwww gpgwww.o $(OBJS) $(LIBS) \ $(PROGS_LDFLAGS_EXTRA) +hashquery: hashquery.o $(CORE_OBJS) $(KEYDB_OBJ) + $(CC) $(LDFLAGS) -o hashquery hashquery.o $(CORE_OBJS) \ + $(KEYDB_OBJ) $(LIBS) $(PROGS_LDFLAGS_EXTRA) + lookup: lookup.o cleankey.o $(CORE_OBJS) $(KEYDB_OBJ) $(CC) $(LDFLAGS) -o lookup lookup.o cleankey.o $(CORE_OBJS) \ $(KEYDB_OBJ) $(LIBS) $(PROGS_LDFLAGS_EXTRA) diff --git a/debian/changelog b/debian/changelog index cb5b863..cd44eb4 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +onak (0.4.0-1+bzr) unstable; urgency=low + + * Development build + + -- Jonathan McDowell Sun, 24 Apr 2011 16:42:15 -0700 + onak (0.4.0-1) unstable; urgency=low * Only seed empty database for if we're using default config diff --git a/hashquery.c b/hashquery.c new file mode 100644 index 0000000..a0f8e1e --- /dev/null +++ b/hashquery.c @@ -0,0 +1,113 @@ +/* + * hashquery.c - CGI to handle SKS style /pks/hashquery requests + * + * Copyright 2011 Jonathan McDowell + */ + +#include +#include +#include +#include +#include + +#include "charfuncs.h" +#include "cleanup.h" +#include "keyid.h" +#include "log.h" +#include "marshal.h" +#include "mem.h" +#include "onak-conf.h" + +void doerror(char *error) +{ + printf("Content-Type: text/plain\n\n"); + printf("%s", error); + cleanuplogthing(); + cleanupconfig(); + exit(EXIT_FAILURE); +} + +int main(int argc, char *argv[]) +{ + char *request_method; + int count, found, i; + uint8_t **hashes; + struct buffer_ctx cgipostbuf; + struct openpgp_publickey **keys; + + readconfig(NULL); + initlogthing("hashquery", config.logfile); + + request_method = getenv("REQUEST_METHOD"); + if (request_method == NULL || strcmp(request_method, "POST") != 0) { + doerror("hashquery must be a HTTP POST request.\n"); + } + + if (!(cgipostbuf.size = atoi(getenv("CONTENT_LENGTH")))) { + doerror("Must provide a content length.\n"); + } + + cgipostbuf.offset = 0; + cgipostbuf.buffer = malloc(cgipostbuf.size); + if (cgipostbuf.buffer == NULL) { + doerror("Couldn't allocate memory for query content.\n"); + } + + if (!fread(cgipostbuf.buffer, cgipostbuf.size, 1, stdin)) { + doerror("Couldn't read query.\n"); + } + + hashes = (uint8_t **) unmarshal_array(buffer_fetchchar, &cgipostbuf, + (void * (*)(int (*)(void *, size_t, void *), void *)) + unmarshal_skshash, &count); + + free(cgipostbuf.buffer); + cgipostbuf.buffer = NULL; + cgipostbuf.size = cgipostbuf.offset = 0; + + if (hashes == NULL) { + doerror("No hashes supplied.\n"); + } + + found = 0; + keys = calloc(sizeof(struct openpgp_publickey *), count); + if (keys == NULL) { + doerror("Couldn't allocate memory for reply.\n"); + } + + if (config.dbbackend->fetch_key_skshash == NULL) { + doerror("Can't fetch by skshash with this backend."); + } + + catchsignals(); + config.dbbackend->initdb(false); + + for (i = 0; i < count; i++) { + config.dbbackend->fetch_key_skshash( + (struct skshash *) hashes[i], &keys[found]); + if (keys[found] != NULL) { + found++; + } + free(hashes[i]); + hashes[i] = NULL; + } + free(hashes); + hashes = NULL; + + config.dbbackend->cleanupdb(); + + puts("Content-Type: pgp/keys\n"); + marshal_array(stdout_putchar, NULL, + (void (*)(int (*)(void *, size_t, void *), + void *, const void *)) + marshal_publickey, (void **) keys, found); + printf("\n"); + + for (i = 0; i < found; i++) { + free_publickey(keys[i]); + } + free(keys); + + cleanuplogthing(); + cleanupconfig(); +} diff --git a/marshal.c b/marshal.c new file mode 100644 index 0000000..2e9b55b --- /dev/null +++ b/marshal.c @@ -0,0 +1,159 @@ +/* + * marshal.c - SKS compatible marshalling routines + * + * Copyright 2011 Jonathan McDowell + */ + +#include +#include +#include +#include + +#include "charfuncs.h" +#include "keyid.h" +#include "keystructs.h" +#include "mem.h" +#include "parsekey.h" + +void marshal_publickey(int (*putchar_func)(void *ctx, size_t count, + void *c), + void *ctx, + const struct openpgp_publickey *key) +{ + uint32_t len; + struct openpgp_packet_list *packets = NULL, *list_end = NULL; + struct buffer_ctx buf; + + buf.buffer = calloc(1, 1024); + buf.size = 1024; + buf.offset = 0; + + flatten_publickey((struct openpgp_publickey *) key, &packets, + &list_end); + write_openpgp_stream(buffer_putchar, &buf, packets); + + len = htonl(buf.offset); + + putchar_func(ctx, sizeof(len), &len); + putchar_func(ctx, buf.offset, buf.buffer); + + free_packet_list(packets); +} + +void marshal_skshash(int (*putchar_func)(void *ctx, size_t count, + void *c), + void *ctx, + const struct skshash *hash) +{ + uint32_t len; + + len = htonl(sizeof(hash->hash)); + + putchar_func(ctx, sizeof(len), &len); + putchar_func(ctx, sizeof(hash->hash), (void *) hash->hash); +} + +struct skshash *unmarshal_skshash(int (*getchar_func)(void *ctx, size_t count, + void *c), + void *ctx) +{ + uint32_t len; + struct skshash *hash; + + if (getchar_func(ctx, sizeof(len), &len)) { + return NULL; + } + len = ntohl(len); + if (len > sizeof(struct skshash)) { + return NULL; + } + hash = calloc(sizeof(struct skshash), 1); + if (getchar_func(ctx, len, hash->hash)) { + free(hash); + return NULL; + } + + return hash; +} + +void marshal_string(int (*putchar_func)(void *ctx, size_t count, + void *c), + void *ctx, + const char *string) +{ + uint32_t len, nlen; + + len = strlen(string); + nlen = htonl(len); + + putchar_func(ctx, sizeof(nlen), &nlen); + putchar_func(ctx, len, &string); +} + +char *unmarshal_string(int (*getchar_func)(void *ctx, size_t count, + void *c), + void *ctx) +{ + uint32_t len; + char *string; + + if (getchar_func(ctx, sizeof(len), &len)) { + return NULL; + } + len = ntohl(len); + string = malloc(len + 1); + if (getchar_func(ctx, len, string)) { + free(string); + return NULL; + } + + string[len] = 0; + return string; +} + +void marshal_array(int (*putchar_func)(void *ctx, size_t count, + void *c), + void *ctx, + void (*marshal_func)(int + (*putchar_func)(void *ctx, + size_t count, void *c), + void *ctx, const void *item), + void **array, + int size) +{ + uint32_t len; + int i; + + len = htonl(size); + + putchar_func(ctx, sizeof(len), &len); + + for (i = 0; i < size; i++) { + marshal_func(putchar_func, ctx, array[i]); + } +} + +void **unmarshal_array(int (*getchar_func)(void *ctx, size_t count, + void *c), + void *ctx, + void *(*unmarshal_func)(int + (*getchar_func)(void *ctx, + size_t count, void *c), + void *ctx), + int *size) +{ + uint32_t len; + void **array; + int i; + + if (getchar_func(ctx, sizeof(len), &len)) { + return NULL; + } + *size = ntohl(len); + array = malloc(*size * sizeof(void *)); + for (i = 0; i < *size; i++) { + array[i] = unmarshal_func(getchar_func, ctx); + } + + return array; +} diff --git a/marshal.h b/marshal.h new file mode 100644 index 0000000..432e51d --- /dev/null +++ b/marshal.h @@ -0,0 +1,137 @@ +/* + * marshal.h - SKS compatible marshalling routines + * + * Copyright 2011 Jonathan McDowell + */ + +#ifndef __MARSHAL_H__ +#define __MARSHAL_H__ + +#include "keyid.h" +#include "keystructs.h" + +/** + * marshal_publickey - Output an OpenPGP key as a byte stream + * @putchar_func: The function to put the next character to the stream + * @ctx: A pointer to the context structure for putchar_func. + * @key: The key to output. + * + * Takes an OpenPGP key and marshals it to a byte stream - writes + * a 32 bit size of the forthcoming data in network byte order and + * then the flattened byte representation of the key. + */ +void marshal_publickey(int (*putchar_func)(void *ctx, size_t count, + void *c), + void *ctx, + const struct openpgp_publickey *key); + +/** + * unmarshal_publickey - Turn a byte stream into an OpenPGP key + * @getchar_func: The function to get the next character from the stream + * @ctx: A pointer to the context structure for getchar_func. + * + * Returns an OpenPGP structure which is the unmarshalled result of + * the input byte stream - ie the inverse of marshal_publickey. + */ +struct openpgp_publickey *unmarshal_publickey(int (*getchar_func)(void *ctx, + size_t count, + void *c), + void *ctx); + +/** + * marshal_skshash - Output an SKS hash as a byte stream + * @putchar_func: The function to put the next character to the stream + * @ctx: A pointer to the context structure for putchar_func. + * @hash: The hash to output. + * + * Takes an SKS hash and marshals it to a byte stream - writes + * a 32 bit size of the forthcoming data (16 bytes) in network byte order + * and then the byte representation of the hash. + */ +void marshal_skshash(int (*putchar_func)(void *ctx, size_t count, + void *c), + void *ctx, + const struct skshash *hash); + +/** + * unmarshal_skshash - Turn a byte stream into an SKS hash structure + * @getchar_func: The function to get the next character from the stream + * @ctx: A pointer to the context structure for getchar_func. + * + * Returns an SKS hash structure which is the unmarshalled result of + * the input byte stream - ie the inverse of marshal_skshash. + */ +struct skshash *unmarshal_skshash(int (*getchar_func)(void *ctx, size_t count, + void *c), + void *ctx); + +/** + * marshal_string - Output a string as a byte stream + * @putchar_func: The function to put the next character to the stream + * @ctx: A pointer to the context structure for putchar_func. + * @string: The string to output. + * + * Takes a string and marshals it to a byte stream - writes a 32 bit size + * of the forthcoming data in network byte order and then the string. + */ +void marshal_string(int (*putchar_func)(void *ctx, size_t count, + void *c), + void *ctx, + const char *string); + +/** + * unmarshal_string - Turn a byte stream into a string + * @getchar_func: The function to get the next character from the stream + * @ctx: A pointer to the context structure for getchar_func. + * + * Returns a string which is the unmarshalled result of the input byte + * stream - ie the inverse of marshal_string. + */ +char *unmarshal_string(int (*getchar_func)(void *ctx, size_t count, + void *c), + void *ctx); + +/** + * marshal_array - Outputs an array as a byte stream + * @putchar_func: The function to put the next character to the stream + * @ctx: A pointer to the context structure for putchar_func. + * @marshal_func: The function to use to marshal each array element. + * @array: A pointer to the array to marshal + * @size:: The number of elements in the array. + * + * Takes an array and marshals it into a byte stream. Outputs a 32 bit + * count of the elements in the array in network byte order and then + * calls marshal_func for each element in the array to provide the + * marshalled contents. + */ +void marshal_array(int (*putchar_func)(void *ctx, size_t count, + void *c), + void *ctx, + void (*marshal_func)(int + (*putchar_func)(void *ctx, + size_t count, void *c), + void *ctx, const void *item), + void **array, + int size); + +/** + * unmarshal_array - Turn a byte stream into an array of elements + * @getchar_func: The function to get the next character from the stream + * @ctx: A pointer to the context structure for getchar_func. + * @unmarshal_func: The function to use to unmarshal each array element. + * @size: A pointer to where to store the number of elements unmarshalled + * + * Takes a byte stream and unmarshals it into an array of elements, + * as determined by the supplied unmarshal_func function. ie the reverse + * of marshal_array. + */ +void **unmarshal_array(int (*getchar_func)(void *ctx, size_t count, + void *c), + void *ctx, + void *(*unmarshal_func)(int + (*getchar_func)(void *ctx, + size_t count, void *c), + void *ctx), + int *size); + +#endif /* __MARSHAL_H__ */ -- 2.30.2