]> git.sommitrealweird.co.uk Git - onak.git/blobdiff - keyd.c
Switch debian build system to dh
[onak.git] / keyd.c
diff --git a/keyd.c b/keyd.c
index 7b6226e3877abbd8c885e3763667f18d72500bba..e43115d48bdda7cb26f81628f563e4324f937698 100644 (file)
--- a/keyd.c
+++ b/keyd.c
 /*
  * keyd.c - key retrieval daemon
  *
- * Jonathan McDowell <noodles@earth.li>
- * 
- * Copyright 2004 Project Purple
+ * Copyright 2004,2011 Jonathan McDowell <noodles@earth.li>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
+#include <errno.h>
 #include <fcntl.h>
+#include <getopt.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/select.h>
 #include <sys/socket.h>
 #include <sys/types.h>
 #include <sys/un.h>
+#include <time.h>
 #include <unistd.h>
 
 #include "charfuncs.h"
 #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"
+#include "version.h"
+
+static struct keyd_stats *stats;
+
+void daemonize(void)
+{
+       pid_t pid;
+
+       pid = fork();
+
+       if (pid < 0) {
+               logthing(LOGTHING_CRITICAL,
+                       "Failed to fork into background: %d (%s)",
+                       errno,
+                       strerror(errno));
+               exit(EXIT_FAILURE);
+       } else if (pid > 0) {
+               logthing(LOGTHING_INFO, "Backgrounded as pid %d.", pid);
+               exit(EXIT_SUCCESS);
+       }
+
+       pid = setsid();
+
+       freopen("/dev/null", "r", stdin);
+       freopen("/dev/null", "w", stdout);
+       freopen("/dev/null", "w", stderr);
+
+       return;
+}
+
+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;
+       uint64_t                    keyid;
+
+       if (key != NULL) {
+               storebuf.offset = 0;
+               storebuf.size = 8192;
+               storebuf.buffer = malloc(8192);
+
+               get_keyid(key, &keyid);
+               logthing(LOGTHING_TRACE,
+                               "Iterating over 0x%016" PRIX64 ".",
+                               keyid);
+
+               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)
 {
@@ -52,7 +143,7 @@ int sock_init(const char *sockname)
 
 int sock_do(int fd)
 {
-       int      cmd = KEYD_CMD_UNKNOWN;
+       uint32_t cmd = KEYD_CMD_UNKNOWN;
        ssize_t  bytes = 0;
        ssize_t  count = 0;
        int      ret = 0;
@@ -62,6 +153,7 @@ int sock_do(int fd)
        struct openpgp_packet_list *packets = NULL;
        struct openpgp_packet_list *list_end = NULL;
        struct buffer_ctx storebuf;
+       struct skshash hash;
 
        /*
         * Get the command from the client.
@@ -75,10 +167,17 @@ int sock_do(int fd)
        }
        
        if (ret == 0) {
+               if (cmd < KEYD_CMD_LAST) {
+                       stats->command_stats[cmd]++;
+               } else {
+                       stats->command_stats[KEYD_CMD_UNKNOWN]++;
+               }
                switch (cmd) {
                case KEYD_CMD_VERSION:
                        cmd = KEYD_REPLY_OK;
                        write(fd, &cmd, sizeof(cmd));
+                       cmd = sizeof(keyd_version);
+                       write(fd, &cmd, sizeof(cmd));
                        write(fd, &keyd_version, sizeof(keyd_version));
                        break;
                case KEYD_CMD_GET:
@@ -91,8 +190,10 @@ int sock_do(int fd)
                        storebuf.offset = 0;
                        if (ret == 0) {
                                logthing(LOGTHING_INFO,
-                                               "Fetching 0x%llX, result: %d",
+                                               "Fetching 0x%" PRIX64
+                                               ", result: %d",
                                                keyid,
+                                               config.dbbackend->
                                                fetch_key(keyid, &key, false));
                                if (key != NULL) {
                                        storebuf.size = 8192;
@@ -140,6 +241,7 @@ int sock_do(int fd)
                                logthing(LOGTHING_INFO,
                                                "Fetching %s, result: %d",
                                                search,
+                                               config.dbbackend->
                                                fetch_key_text(search, &key));
                                if (key != NULL) {
                                        storebuf.size = 8192;
@@ -200,7 +302,7 @@ int sock_do(int fd)
                                                &packets,
                                                0);
                                parse_keys(packets, &key);
-                               store_key(key, false, false);
+                               config.dbbackend->store_key(key, false, false);
                                free_packet_list(packets);
                                packets = NULL;
                                free_publickey(key);
@@ -219,9 +321,11 @@ int sock_do(int fd)
                        }
                        if (ret == 0) {
                                logthing(LOGTHING_INFO,
-                                               "Deleting 0x%llX, result: %d",
+                                               "Deleting 0x%" PRIX64
+                                               ", result: %d",
                                                keyid,
-                                               delete_key(keyid, false));
+                                               config.dbbackend->delete_key(
+                                                       keyid, false));
                        }
                        break;
                case KEYD_CMD_GETFULLKEYID:
@@ -232,16 +336,88 @@ int sock_do(int fd)
                                ret = 1;
                        }
                        if (ret == 0) {
-                               keyid = getfullkeyid(keyid);
+                               keyid = config.dbbackend->getfullkeyid(keyid);
+                               cmd = sizeof(keyid);
+                               write(fd, &cmd, sizeof(cmd));
                                write(fd, &keyid, sizeof(keyid));
                        }
                        break;
+               case KEYD_CMD_KEYITER:
+                       cmd = KEYD_REPLY_OK;
+                       write(fd, &cmd, sizeof(cmd));
+                       config.dbbackend->iterate_keys(iteratefunc,
+                                       &fd);
+                       bytes = 0;
+                       write(fd, &bytes, sizeof(bytes));
+                       break;
                case KEYD_CMD_CLOSE:
+                       cmd = KEYD_REPLY_OK;
+                       write(fd, &cmd, sizeof(cmd));
                        ret = 1;
                        break;
                case KEYD_CMD_QUIT:
+                       cmd = KEYD_REPLY_OK;
+                       write(fd, &cmd, sizeof(cmd));
+                       logthing(LOGTHING_NOTICE,
+                               "Exiting due to quit request.");
+                       ret = 1;
                        trytocleanup();
                        break;
+               case KEYD_CMD_STATS:
+                       cmd = KEYD_REPLY_OK;
+                       write(fd, &cmd, sizeof(cmd));
+                       cmd = sizeof(*stats);
+                       write(fd, &cmd, sizeof(cmd));
+                       write(fd, stats,
+                               sizeof(*stats));
+                       break;
+               case KEYD_CMD_GETSKSHASH:
+                       cmd = KEYD_REPLY_OK;
+                       write(fd, &cmd, sizeof(cmd));
+                       bytes = read(fd, hash.hash, sizeof(hash.hash));
+                       if (bytes != sizeof(hash.hash)) {
+                               ret = 1;
+                       }
+                       storebuf.offset = 0;
+                       if (ret == 0) {
+                               logthing(LOGTHING_INFO,
+                                               "Fetching by hash"
+                                               ", result: %d",
+                                               config.dbbackend->
+                                               fetch_key_skshash(&hash,
+                                                       &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;
+
                default:
                        logthing(LOGTHING_ERROR, "Got unknown command: %d",
                                        cmd);
@@ -255,7 +431,8 @@ int sock_do(int fd)
 
 int sock_close(int fd)
 {
-       return shutdown(fd, SHUT_RDWR);
+       shutdown(fd, SHUT_RDWR);
+       return close(fd);
 }
 
 int sock_accept(int fd)
@@ -272,6 +449,7 @@ int sock_accept(int fd)
        }
 
        if (ret != -1) {
+               stats->connects++;
                while (!sock_do(srv)) ;
                sock_close(srv);
        }
@@ -279,17 +457,65 @@ int sock_accept(int fd)
        return 1;
 }
 
+static void usage(void)
+{
+       puts("keyd " ONAK_VERSION " - backend key serving daemon for the "
+               "onak PGP keyserver.\n");
+       puts("Usage:\n");
+       puts("\tkeyd [options]\n");
+       puts("\tOptions:\n:");
+       puts("-c <file> - use <file> as the config file");
+       puts("-f        - run in the foreground");
+       puts("-h        - show this help text");
+       exit(EXIT_FAILURE);
+}
+
 int main(int argc, char *argv[])
 {
        int fd = -1;
        fd_set rfds;
        char sockname[1024];
+       char *configfile = NULL;
+       bool foreground = false;
+       int optchar;
+
+       while ((optchar = getopt(argc, argv, "c:fh")) != -1 ) {
+               switch (optchar) {
+               case 'c':
+                       configfile = strdup(optarg);
+                       break;
+               case 'f':
+                       foreground = true;
+                       break;
+               case 'h':
+               default:
+                       usage();
+                       break;
+               }
+       }
 
-       readconfig(NULL);
+       readconfig(configfile);
+       free(configfile);
+       configfile = NULL;
        initlogthing("keyd", config.logfile);
+       config.use_keyd = false;
+
+       if (!foreground) {
+               daemonize();
+       }
 
        catchsignals();
-       
+       signal(SIGPIPE, SIG_IGN);
+
+
+       stats = calloc(1, sizeof(*stats));
+       if (!stats) {
+               logthing(LOGTHING_ERROR,
+                       "Couldn't allocate memory for stats structure.");
+               exit(EXIT_FAILURE);
+       }
+       stats->started = time(NULL);
+
        snprintf(sockname, 1023, "%s/%s", config.db_dir, KEYD_SOCKET);
        fd = sock_init(sockname);
 
@@ -297,7 +523,7 @@ int main(int argc, char *argv[])
                FD_ZERO(&rfds);
                FD_SET(fd, &rfds);
 
-               initdb(false);
+               config.dbbackend->initdb(false);
 
                logthing(LOGTHING_NOTICE, "Accepting connections.");
                while (!cleanup() && select(fd + 1, &rfds, NULL, NULL, NULL) != -1) {
@@ -305,13 +531,15 @@ int main(int argc, char *argv[])
                        sock_accept(fd);
                        FD_SET(fd, &rfds);
                }
-               cleanupdb();
+               config.dbbackend->cleanupdb();
                sock_close(fd);
                unlink(sockname);
        }
 
+       free(stats);
+
        cleanuplogthing();
        cleanupconfig();
-       
+
        return(EXIT_SUCCESS);
 }