From: Jonathan McDowell Date: Wed, 6 Apr 2011 04:22:39 +0000 (-0700) Subject: Add keydctl for talking to keyd backend X-Git-Tag: 0.4.0~15 X-Git-Url: https://the.earth.li/gitweb/?a=commitdiff_plain;h=3e3f47ec2fdbfaf0682d9790a99264a4e60e9bf1;p=onak.git Add keydctl for talking to keyd backend The regular keydb functions for talking to keyd work fine for key related operations, but there are extra things we want to do with keyd (such as checking its status or asking it to cleanly exit) that there's no way to do at present. Add keydctl to provide a way to access these additional features. --- diff --git a/Makefile.in b/Makefile.in index 546f3a8..66a3b5c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -28,9 +28,9 @@ SRCS = armor.c parsekey.c merge.c keyid.c md5.c sha1.c main.c getcgi.c mem.c \ PROGS_LDFLAGS_EXTRA = ifeq (x@KEYD@, xyes) -PROGS += keyd +PROGS += keyd keydctl KEYDB_OBJ = keydb_keyd.o -SRCS += keyd.c keydb_keyd.c +SRCS += keyd.c keydb_keyd.c keydctl.c else KEYDB_OBJ = keydb_$(DBTYPE).o endif @@ -38,9 +38,9 @@ endif ifeq (x@DBTYPE@, xdynamic) LIBS += -ldl BACKENDS = $(foreach be,@BACKENDS@,libkeydb_$(be).so) -PROGS += keyd +PROGS += keyd keydctl PROGS_LDFLAGS_EXTRA = -rdynamic -SRCS += keyd.c +SRCS += keyd.c keydctl.c endif OBJS = stats.o cleankey.o $(CORE_OBJS) $(KEYDB_OBJ) @@ -58,17 +58,22 @@ install: $(PROGS) onak.conf $(BACKENDS) install onak-mail.pl $(DESTDIR)/@libdir@/onak install onak splitkeys $(DESTDIR)/@bindir@ install onak.1 splitkeys.1 $(DESTDIR)/@mandir@/man1 - install keyd.8 onak-mail.pl.8 $(DESTDIR)/@mandir@/man8 + install keyd.8 keydctl.8 onak-mail.pl.8 $(DESTDIR)/@mandir@/man8 ifeq (x@DBTYPE@, xdynamic) install $(BACKENDS) $(DESTDIR)/@libdir@/onak/backends install -d $(DESTDIR)/@sbindir@ install keyd $(DESTDIR)/@sbindir@ + install keydctl $(DESTDIR)/@bindir@ endif keyd: keyd.o $(CORE_OBJS) keydb_$(DBTYPE).o $(CC) $(LDFLAGS) $(PROGS_LDFLAGS_EXTRA) \ -o keyd keyd.o $(CORE_OBJS) keydb_$(DBTYPE).o $(LIBS) +keydctl: keydctl.o onak-conf.o ll.o log.o + $(CC) $(LDFLAGS) $(PROGS_LDFLAGS_EXTRA) \ + -o keydctl keydctl.o onak-conf.o ll.o log.o $(LIBS) + libkeydb_db4.so: keydb_db4.o $(CC) -shared $(DB4LIBS) -o libkeydb_db4.so keydb_db4.o $(CORE_OBJS) @@ -118,6 +123,11 @@ onak-conf.o: onak-conf.c onak-conf.h $(CC) $(CFLAGS) -DCONFIGFILE=\"@sysconfdir@/onak.conf\" \ -DDBFUNCS=keydb_@DBTYPE@_funcs -c onak-conf.c +# HACK: onak-conf.o needs to be able to see keydb_@DBTYPE@_funcs, but +# keydctl doesn't want to link against the DB stuff. To be fixed more cleanly. +keydctl.o: keydctl.c keyd.h + $(CC) $(CFLAGS) -DDBFUNCS=keydb_@DBTYPE@_funcs -c keydctl.c + onak-mail.pl: onak-mail.pl.in sed 's:@CONFIG@:@sysconfdir@/onak.conf:g' < onak-mail.pl.in > onak-mail.pl chmod +x onak-mail.pl diff --git a/keydctl.8 b/keydctl.8 new file mode 100644 index 0000000..44e7ba6 --- /dev/null +++ b/keydctl.8 @@ -0,0 +1,50 @@ +.TH KEYD 8 +.SH NAME +keydctl \- control an onak keyd instance +.SH SYNOPSIS +.PP +.B keydctl +[ +.B options +] +.B command +.SH DESCRIPTION +.PP +keydctl is a command line client for interacting with a backend keyd +daemon. It's intended to perform functions that are specifically related +to keyd rather than being generic keyserver functions. See +.BR onak(1) +for details about how to perform key related operations. +.SS "Options" +.TP +\fB\-c \fIFILE\fR\fR +Use \fIFILE\fR as the config file instead of the default. +.TP +\fB\-h\fR +Display help text. +.SS "Commands" +.TP +.B check +Query if keyd is running and accepting commands. Returns 0 if it is, 1 +otherwise. Outputs nothing to stdout/stderr. +.TP +.B quit +Request that keyd exits cleanly +.TP +.B status +Display the status of a running keyd. Currently just the protocol version +in use. +.SH FILES +.br +.nf +.\" set tabstop to longest possible filename, plus a wee bit +.ta \w'/usr/lib/perl/getopts.pl 'u +\fI/etc/onak.conf\fR default configuration file +.SH NOTES +This man page could probably do with some more details. +.SH "SEE ALSO" +.BR onak (1) +.BR keyd (8) +.SH AUTHOR +onak was written by Jonathan McDowell . It can be found at +http://www.earth.li/projectpurple/progs/onak.html diff --git a/keydctl.c b/keydctl.c new file mode 100644 index 0000000..b786fea --- /dev/null +++ b/keydctl.c @@ -0,0 +1,202 @@ +/* + * keydctl.c - A simple program to control a running keyd instance + * + * Copyright 2011 Jonathan McDowell + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "keyd.h" +#include "onak-conf.h" + +/* HACK: We need to stop onak-conf.o requiring this. */ +void *DBFUNCS = NULL; + +static int keyd_fd = -1; +static int verbose = 0; + +static int keyd_do_command(enum keyd_ops cmd, void *buf, size_t len) +{ + uint32_t tmp; + + if (keyd_fd < 0) { + return -1; + } + + tmp = cmd; + if (write(keyd_fd, &tmp, sizeof(tmp)) != sizeof(tmp)) { + if (verbose >= 0) { + fprintf(stderr, + "Couldn't write keyd command %d: %s (%d)\n", + cmd, strerror(errno), errno); + } + exit(EXIT_FAILURE); + } else if (read(keyd_fd, &tmp, sizeof(tmp)) != sizeof(tmp)) { + if (verbose >= 0) { + fprintf(stderr, + "Couldn't read keyd command %d reply: " + "%s (%d)\n", + cmd, strerror(errno), errno); + } + exit(EXIT_FAILURE); + } else if (tmp != KEYD_REPLY_OK) { + return -1; + } else if (buf == NULL) { + return 0; + } else if (read(keyd_fd, &tmp, sizeof(tmp)) != sizeof(tmp)) { + if (verbose >= 0) { + fprintf(stderr, + "Couldn't read keyd command %d reply length: " + "%s (%d)\n", + cmd, strerror(errno), errno); + } + exit(EXIT_FAILURE); + } else if (tmp > len) { + /* TODO: Read what we can into buf and skip the rest */ + return -1; + } else { + return read(keyd_fd, buf, tmp); + } +} + +static void keyd_connect(void) +{ + struct sockaddr_un sock; + uint32_t reply = KEYD_REPLY_UNKNOWN_CMD; + + keyd_fd = socket(PF_UNIX, SOCK_STREAM, 0); + if (keyd_fd < 0) { + if (verbose >= 0) { + fprintf(stderr, + "Couldn't open socket: %s (%d)\n", + 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) { + if (verbose >= 0) { + fprintf(stderr, + "Couldn't connect to socket %s: %s (%d)\n", + sock.sun_path, + strerror(errno), + errno); + } + exit(EXIT_FAILURE); + } + + keyd_do_command(KEYD_CMD_VERSION, &reply, sizeof(reply)); + if (reply != keyd_version) { + if (verbose >= 0) { + fprintf(stderr, "Error! keyd protocol version " + "mismatch. (us = %d, it = %d)\n", + keyd_version, reply); + } + exit(EXIT_FAILURE); + } + + return; +} + +static void keyd_close(void) +{ + uint32_t cmd = KEYD_CMD_CLOSE; + + if (write(keyd_fd, &cmd, sizeof(cmd)) != sizeof(cmd) && verbose >= 0) { + fprintf(stderr, "Couldn't send close cmd: %s (%d)\n", + strerror(errno), + errno); + } + + if (shutdown(keyd_fd, SHUT_RDWR) < 0 && verbose >= 0) { + fprintf(stderr, "Error shutting down socket: %d\n", + errno); + } + if (close(keyd_fd) < 0 && verbose >= 0) { + fprintf(stderr, "Error closing down socket: %d\n", + errno); + } + keyd_fd = -1; + + return; + +} + +static void keyd_status(void) +{ + uint32_t reply; + + keyd_do_command(KEYD_CMD_VERSION, &reply, sizeof(reply)); + printf("Using keyd protocol version %d.\n", reply); + + return; +} + +static void usage(void) +{ + puts("keydctl " PACKAGE_VERSION " - control an onak keyd instance.\n"); + puts("Usage:\n"); + puts("\tonak [options] \n"); + puts("\tCommands:\n"); + puts("\tcheck - check if keyd is running"); + puts("\tquit - request that keyd cleanly shuts down"); + puts("\tstatus - display running keyd status"); + exit(EXIT_FAILURE); +} + +int main(int argc, char *argv[]) +{ + int optchar; + char *configfile = NULL; + + while ((optchar = getopt(argc, argv, "c:h")) != -1 ) { + switch (optchar) { + case 'c': + configfile = strdup(optarg); + break; + case 'h': + default: + usage(); + break; + } + } + + readconfig(configfile); + free(configfile); + configfile = NULL; + + if ((argc - optind) < 1) { + usage(); + } else if (!strcmp("check", argv[optind])) { + /* Just do the connect and close quietly */ + verbose = -1; + keyd_connect(); + keyd_close(); + } else if (!strcmp("status", argv[optind])) { + keyd_connect(); + keyd_status(); + keyd_close(); + } else if (!strcmp("quit", argv[optind])) { + keyd_connect(); + keyd_do_command(KEYD_CMD_QUIT, NULL, 0); + keyd_close(); + } else { + usage(); + } + + + exit(EXIT_SUCCESS); +}