Add /pks/hashquery
authorJonathan McDowell <noodles@earth.li>
Mon, 25 Apr 2011 04:49:32 +0000 (21:49 -0700)
committerJonathan McDowell <noodles@earth.li>
Mon, 25 Apr 2011 04:49:32 +0000 (21:49 -0700)
  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
Makefile.in
debian/changelog
hashquery.c [new file with mode: 0644]
marshal.c [new file with mode: 0644]
marshal.h [new file with mode: 0644]

index d6678dec0663052f7d1bc167c224f69409eaf5fd..2083983db81dccfac693aa308992d140f6b7e11d 100644 (file)
@@ -5,6 +5,7 @@ config.log
 config.h
 config.h.in
 add
+hashquery
 lookup
 onak
 gpgwww
index 867245dcbcc06ea0a2fdfd9c784202c05d05144a..1fb16d9426478d0100128c3f07ce4e6f44085aa6 100644 (file)
@@ -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)
index cb5b86344ee6d2c7867e81b310739d7b24b49612..cd44eb460f57fc911c56e677fcedc23ecffac292 100644 (file)
@@ -1,3 +1,9 @@
+onak (0.4.0-1+bzr) unstable; urgency=low
+
+  * Development build
+
+ -- Jonathan McDowell <noodles@earth.li>  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 (file)
index 0000000..a0f8e1e
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * hashquery.c - CGI to handle SKS style /pks/hashquery requests
+ *
+ * Copyright 2011 Jonathan McDowell <noodles@earth.li>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#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 (file)
index 0000000..2e9b55b
--- /dev/null
+++ b/marshal.c
@@ -0,0 +1,159 @@
+/*
+ * marshal.c - SKS compatible marshalling routines
+ *
+ * Copyright 2011 Jonathan McDowell <noodles@earth.li>
+ */
+
+#include <arpa/inet.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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 (file)
index 0000000..432e51d
--- /dev/null
+++ b/marshal.h
@@ -0,0 +1,137 @@
+/*
+ * marshal.h - SKS compatible marshalling routines
+ *
+ * Copyright 2011 Jonathan McDowell <noodles@earth.li>
+ */
+
+#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__ */