From 17366b5296920cd37f716426fd7c653063dd5d78 Mon Sep 17 00:00:00 2001 From: Rob Austein Date: Wed, 4 Jan 2017 18:52:51 -0500 Subject: Convert "daemon" mode of C client code to use Python RPC MUX. --- Makefile | 13 +-- cryptech_rpcmuxd | 0 daemon.c | 330 ---------------------------------------------------- hal_internal.h | 2 +- rpc_client_daemon.c | 41 +++++-- 5 files changed, 34 insertions(+), 352 deletions(-) mode change 100644 => 100755 cryptech_rpcmuxd delete mode 100644 daemon.c diff --git a/Makefile b/Makefile index c0a136b..1e7316a 100644 --- a/Makefile +++ b/Makefile @@ -144,16 +144,12 @@ endif # the C preprocessor: we can use symbolic names so long as they're defined as macros # in the C code, but we can't use things like C enum symbols. -ifneq "${RPC_MODE}" "server" - OBJ += rpc_serial.o -endif - RPC_CLIENT_OBJ = rpc_client.o ifeq "${RPC_TRANSPORT}" "loopback" RPC_CLIENT_OBJ += rpc_client_loopback.o else ifeq "${RPC_TRANSPORT}" "serial" - RPC_CLIENT_OBJ += rpc_client_serial.o + RPC_CLIENT_OBJ += rpc_serial.o rpc_client_serial.o else ifeq "${RPC_TRANSPORT}" "daemon" RPC_CLIENT_OBJ += rpc_client_daemon.o endif @@ -225,13 +221,10 @@ server: serial: ${MAKE} RPC_MODE=client-mixed RPC_TRANSPORT=serial -daemon: mixed cryptech_rpcd +daemon: mixed .PHONY: client mixed server serial daemon -cryptech_rpcd: daemon.o ${LIB} - ${CC} ${CFLAGS} -o $@ $^ ${LDFLAGS} - ${OBJ}: ${INC} ${LIB}: ${OBJ} @@ -251,7 +244,7 @@ test: all cd tests; ${MAKE} -k $@ clean: - rm -f *.o ${LIB} cryptech_rpcd + rm -f *.o ${LIB} cd tests; ${MAKE} $@ cd utils; ${MAKE} $@ diff --git a/cryptech_rpcmuxd b/cryptech_rpcmuxd old mode 100644 new mode 100755 diff --git a/daemon.c b/daemon.c deleted file mode 100644 index ff95353..0000000 --- a/daemon.c +++ /dev/null @@ -1,330 +0,0 @@ -#define DEBUG -/* - * daemon.c - * -------- - * A daemon to arbitrate shared access to a serial connection to the HSM. - * - * Copyright (c) 2016, NORDUnet A/S All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the NORDUnet nor the names of its contributors may - * be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include /* required with -std=c99 */ -#include /* for default speed */ - -#include "hal_internal.h" -#include "slip_internal.h" -#include "xdr_internal.h" - -static char usage[] = - "usage: %s [-n socketname] [-d ttydevice] [-s ttyspeed]\n"; - -/* - * Work around glibc "feature test" insanity. This isn't the correct - * definition according to the POSIX, but it does what seems to be the - * normal hack on Linux (where this is broken more often than not). - */ - -#ifndef SUN_LEN -#define SUN_LEN(_sun_ptr_) (sizeof(*(_sun_ptr_))) -#endif - -/* select() is hopelessly broken, and epoll() is Linux-specific, so we'll use - * poll() until such a time as libevent or libev seems more appropriate. - * Unfortunately, poll() doesn't come with any macros or functions to manage - * the pollfd array, so we have to invent them. - */ - -static struct pollfd *pollfds = NULL; -static nfds_t nfds = 0; -static nfds_t npollfds = 0; - -static void poll_add(int fd) -{ - /* add 4 entries at a time to avoid having to realloc too often */ -#define NNEW 4 - - /* expand the array if necessary */ - if (nfds == npollfds) { - npollfds = nfds + NNEW; - pollfds = realloc(pollfds, npollfds * sizeof(struct pollfd)); - if (pollfds == NULL) { - perror("realloc"); - exit(EXIT_FAILURE); - } - /* zero the new entries for hygiene */ - memset(&pollfds[nfds], 0, NNEW * sizeof(struct pollfd)); - } - - /* populate the new entry */ - pollfds[nfds].fd = fd; - pollfds[nfds].events = POLLIN; - ++nfds; -} - -static void poll_remove(int fd) -{ - nfds_t i; - - /* search the pollfd array */ - for (i = 0; i < nfds; ++i) { - if (pollfds[i].fd == fd) { - /* shift remainder of the array left by one */ - memmove(&pollfds[i], &pollfds[i + 1], (nfds - i - 1) * sizeof(struct pollfd)); - /* zero the last entry for hygiene */ - memset(&pollfds[nfds - 1], 0, sizeof(struct pollfd)); - --nfds; - return; - } - } - /* if it's not found, return without an error */ -} - -typedef struct { - size_t len; - uint8_t buf[HAL_RPC_MAX_PKT_SIZE]; -} rpc_buffer_t; -static rpc_buffer_t ibuf, obuf; - -const char *socket_name = HAL_CLIENT_DAEMON_DEFAULT_SOCKET_NAME; - -/* Set up an atexit handler to remove the filesystem entry for the unix domain - * socket. This will trigger on error exits, but not on the "normal" SIGKILL. - */ -void atexit_cleanup(void) -{ - unlink(socket_name); -} - -#ifdef DEBUG -static void hexdump(uint8_t *buf, uint32_t len) -{ - for (uint32_t i = 0; i < len; ++i) - printf("%02x%c", buf[i], ((i & 0x07) == 0x07) ? '\n' : ' '); - if ((len & 0x07) != 0) - printf("\n"); -} -#endif - -int main(int argc, char *argv[]) -{ - struct sockaddr_un name; - int ret; - int lsock; - int dsock; - int opt; - const char *device = getenv(HAL_CLIENT_SERIAL_DEVICE_ENVVAR); - const char *speed_ = getenv(HAL_CLIENT_SERIAL_SPEED_ENVVAR); - uint32_t speed = HAL_CLIENT_SERIAL_DEFAULT_SPEED; - - if (device == NULL) - device = HAL_CLIENT_SERIAL_DEFAULT_DEVICE; - - if (speed_ != NULL) - speed = (uint32_t) strtoul(speed_, NULL, 10); - - while ((opt = getopt(argc, argv, "hn:d:s:")) != -1) { - switch (opt) { - case 'h': - printf(usage, argv[0]); - exit(EXIT_SUCCESS); - case 'n': - socket_name = optarg; - break; - case 'd': - device = optarg; - break; - case 's': - speed = (uint32_t) strtoul(optarg, NULL, 10); - switch (speed) { - case 115200: - case 921600: - break; - default: - printf("invalid speed value %s\n", optarg); - exit(EXIT_FAILURE); - } - break; - default: - printf(usage, argv[0]); - exit(EXIT_FAILURE); - } - } - - if (atexit(atexit_cleanup) != 0) { - perror("atexit"); - exit(EXIT_FAILURE); - } - - if (hal_serial_init(device, speed) != HAL_OK) - exit(EXIT_FAILURE); - - int serial_fd = hal_serial_get_fd(); - poll_add(serial_fd); - - /* Remove the filesystem entry for the unix domain socket. The usual way - * to stop a daemon is SIGKILL, which we can't catch, so the file remains, - * and will prevent us from binding the socket. - * - * XXX We should also scan the process table, to make sure the daemon - * isn't already running. - */ - unlink(socket_name); - - /* Create the listening socket. - */ - lsock = socket(AF_UNIX, SOCK_SEQPACKET, 0); - if (lsock == -1) { - perror("socket"); - exit(EXIT_FAILURE); - } - poll_add(lsock); - - /* For portability, clear the whole address structure, since some - * implementations have additional (nonstandard) fields in the structure. - */ - memset(&name, 0, sizeof(struct sockaddr_un)); - - /* Bind the listening socket. On some platforms, we have to pass the "real" - * (number of bytes in use) length of the sockaddr_un to get the name bound - * correctly, so use the SUN_LEN() macro to calculate that. - */ - name.sun_family = AF_UNIX; - strncpy(name.sun_path, socket_name, sizeof(name.sun_path) - 1); - ret = bind(lsock, (const struct sockaddr *) &name, SUN_LEN(&name)); - if (ret == -1) { - perror("bind"); - exit(EXIT_FAILURE); - } - - /* Prepare to accept connections. - */ - ret = listen(lsock, 20); - if (ret == -1) { - perror("listen"); - exit(EXIT_FAILURE); - } - - /* The main loop. - */ - for (;;) { - - /* Blocking poll on all descriptors of interest. - */ - ret = poll(pollfds, nfds, -1); - if (ret == -1) { - perror("poll"); - exit(EXIT_FAILURE); - } - - for (nfds_t i = 0; i < nfds; ++i) { - if (pollfds[i].revents != 0) { - /* XXX POLLERR|POLLHUP|POLLNVAL */ - - /* serial port */ - if (pollfds[i].fd == serial_fd) { - int complete; - hal_slip_recv_char(ibuf.buf, &ibuf.len, sizeof(ibuf.buf), &complete); - if (complete) { -#ifdef DEBUG - printf("serial port received response:\n"); - hexdump(ibuf.buf, ibuf.len); -#endif - /* We've got a complete rpc response packet. */ - const uint8_t *bufptr = ibuf.buf + 4; - const uint8_t * const limit = ibuf.buf + ibuf.len; - uint32_t sock; - /* Second word of the response is the client ID. */ - hal_xdr_decode_int(&bufptr, limit, &sock); - /* Pass response on to the client that requested it. */ - send(sock, ibuf.buf, ibuf.len, 0); - /* Reinitialize the receive buffer. */ - memset(&ibuf, 0, sizeof(ibuf)); - } - } - - /* listening socket */ - else if (pollfds[i].fd == lsock) { - /* Accept incoming connection. */ - dsock = accept(lsock, NULL, NULL); - if (ret == -1) { - perror("accept"); - exit(EXIT_FAILURE); - } - poll_add(dsock); -#ifdef DEBUG - printf("listening socket accept data socket %d\n", dsock); -#endif - } - - /* client data socket */ - else { - const uint8_t * const limit = obuf.buf + HAL_RPC_MAX_PKT_SIZE; - /* Get the client's rpc request packet. */ - obuf.len = recv(pollfds[i].fd, obuf.buf, HAL_RPC_MAX_PKT_SIZE, 0); -#ifdef DEBUG - printf("data socket %d received request:\n", pollfds[i].fd); - hexdump(obuf.buf, obuf.len); -#endif - - /* Fill in the client handle arg - first field after opcode. */ - uint8_t *bufptr = obuf.buf + 4; - hal_xdr_encode_int(&bufptr, limit, pollfds[i].fd); - - if (obuf.len > 0) { -#ifdef DEBUG - printf("passing to serial port:\n"); - hexdump(obuf.buf, obuf.len); -#endif - /* Pass it on to the serial port. */ - hal_slip_send(obuf.buf, obuf.len); - } - else { -#ifdef DEBUG - printf("closing data socket\n"); -#endif - /* Client has closed the socket. */ - close(pollfds[i].fd); - poll_remove(pollfds[i].fd); - } - /* Reinitialize the transmit buffer. */ - memset(&obuf, 0, sizeof(obuf)); - } - } - } - } - - /*NOTREACHED*/ - exit(EXIT_SUCCESS); -} diff --git a/hal_internal.h b/hal_internal.h index a8f88e2..ef3dd49 100644 --- a/hal_internal.h +++ b/hal_internal.h @@ -880,7 +880,7 @@ typedef enum { */ #ifndef HAL_CLIENT_DAEMON_DEFAULT_SOCKET_NAME -#define HAL_CLIENT_DAEMON_DEFAULT_SOCKET_NAME "/tmp/cryptech_rpcd.socket" +#define HAL_CLIENT_DAEMON_DEFAULT_SOCKET_NAME "/tmp/.cryptech_rpcmuxd" #endif /* diff --git a/rpc_client_daemon.c b/rpc_client_daemon.c index dea352f..7ff3f21 100644 --- a/rpc_client_daemon.c +++ b/rpc_client_daemon.c @@ -45,17 +45,18 @@ static int sock = -1; hal_error_t hal_rpc_client_transport_init(void) { + const char *sockname = getenv("CRYPTECH_RPC_CLIENT_SOCKET_NAME"); struct sockaddr_un name; - int ret; - sock = socket(AF_UNIX, SOCK_SEQPACKET, 0); + sock = socket(AF_UNIX, SOCK_STREAM, 0); if (sock == -1) return perror("socket"), HAL_ERROR_RPC_TRANSPORT; + if (sockname == NULL) + sockname = HAL_CLIENT_DAEMON_DEFAULT_SOCKET_NAME; memset(&name, 0, sizeof(struct sockaddr_un)); name.sun_family = AF_UNIX; - strncpy(name.sun_path, HAL_CLIENT_DAEMON_DEFAULT_SOCKET_NAME, sizeof(name.sun_path) - 1); - ret = connect(sock, (const struct sockaddr *) &name, sizeof(struct sockaddr_un)); - if (ret == -1) + strncpy(name.sun_path, sockname, sizeof(name.sun_path) - 1); + if (connect(sock, (const struct sockaddr *) &name, sizeof(struct sockaddr_un)) < 0) return perror("connect"), HAL_ERROR_RPC_TRANSPORT; return HAL_OK; } @@ -69,17 +70,35 @@ hal_error_t hal_rpc_client_transport_close(void) return HAL_OK; } + hal_error_t hal_rpc_send(const uint8_t * const buf, const size_t len) { - ssize_t ret = send(sock, (const void *)buf, len, 0); - return (ret == -1) ? HAL_ERROR_RPC_TRANSPORT : HAL_OK; + return hal_slip_send(buf, len); } hal_error_t hal_rpc_recv(uint8_t * const buf, size_t * const len) { - ssize_t ret = recv(sock, (void *)buf, *len, 0); - if (ret == -1) - return HAL_ERROR_RPC_TRANSPORT; - *len = (size_t)ret; + size_t maxlen = *len; + *len = 0; + hal_error_t err = hal_slip_recv(buf, len, maxlen); + return err; +} + +/* + * These two are sort of mis-named, fix eventually, but this is what + * the code in slip.c expects. + */ + +hal_error_t hal_serial_send_char(const uint8_t c) +{ + if (write(sock, &c, 1) != 1) + return perror("write"), HAL_ERROR_RPC_TRANSPORT; + return HAL_OK; +} + +hal_error_t hal_serial_recv_char(uint8_t * const c) +{ + if (read(sock, c, 1) != 1) + return perror("read"), HAL_ERROR_RPC_TRANSPORT; return HAL_OK; } -- cgit v1.2.3