summary refs log tree commit diff
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2019-11-01 01:38:50 -0400
committerJune McEnroe <june@causal.agency>2019-11-01 01:38:50 -0400
commit4e465eacef72a3b4c822c8baee9d2ccca78e6cd1 (patch)
tree26279b6f0fdb626afc91f413306e5f8a4e2bb6bc
parentRe-read cert and key from the same FILEs (diff)
downloadpounce-4e465eacef72a3b4c822c8baee9d2ccca78e6cd1.tar.gz
pounce-4e465eacef72a3b4c822c8baee9d2ccca78e6cd1.zip
Reload certificates using openat
This is more versatile since files are more likely to be replaced than
overwritten.
-rw-r--r--bounce.c103
-rw-r--r--listen.c8
2 files changed, 69 insertions, 42 deletions
diff --git a/bounce.c b/bounce.c
index a5b448a..f9a4235 100644
--- a/bounce.c
+++ b/bounce.c
@@ -19,6 +19,7 @@
 #include <assert.h>
 #include <err.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <getopt.h>
 #include <limits.h>
 #include <poll.h>
@@ -42,9 +43,52 @@
 #define SIGINFO SIGUSR2
 #endif
 
-static volatile sig_atomic_t signals[NSIG];
-static void signalHandler(int signal) {
-	signals[signal] = 1;
+static FILE *saveFile;
+
+static void saveExit(void) {
+	int error = ringSave(saveFile);
+	if (error) warn("fwrite");
+	error = fclose(saveFile);
+	if (error) warn("fclose");
+}
+
+static void saveLoad(const char *path) {
+	umask(0066);
+	saveFile = fopen(path, "a+");
+	if (!saveFile) err(EX_CANTCREAT, "%s", path);
+
+	int error = flock(fileno(saveFile), LOCK_EX | LOCK_NB);
+	if (error && errno != EWOULDBLOCK) err(EX_OSERR, "flock");
+	if (error) errx(EX_CANTCREAT, "%s: lock held by other process", path);
+
+	rewind(saveFile);
+	ringLoad(saveFile);
+
+	error = ftruncate(fileno(saveFile), 0);
+	if (error) err(EX_IOERR, "ftruncate");
+
+	atexit(saveExit);
+}
+
+static char *openParent(int *dir, char *path) {
+	char *file = strrchr(path, '/');
+	if (file) {
+		*file++ = '\0';
+		*dir = open(path, O_DIRECTORY);
+	} else {
+		file = path;
+		*dir = open(".", O_DIRECTORY);
+	}
+	if (*dir < 0) err(EX_NOINPUT, "%s", path);
+	return file;
+}
+
+static FILE *fopenat(int dir, const char *path) {
+	int fd = openat(dir, path, O_RDONLY);
+	if (fd < 0) err(EX_NOINPUT, "%s", path);
+	FILE *file = fdopen(fd, "r");
+	if (!file) err(EX_IOERR, "fdopen");
+	return file;
 }
 
 static struct {
@@ -74,31 +118,9 @@ static void eventRemove(size_t i) {
 	event.clients[i] = event.clients[event.len];
 }
 
-static FILE *saveFile;
-
-static void saveExit(void) {
-	int error = ringSave(saveFile);
-	if (error) warn("fwrite");
-	error = fclose(saveFile);
-	if (error) warn("fclose");
-}
-
-static void saveLoad(const char *path) {
-	umask(0066);
-	saveFile = fopen(path, "a+");
-	if (!saveFile) err(EX_CANTCREAT, "%s", path);
-
-	int error = flock(fileno(saveFile), LOCK_EX | LOCK_NB);
-	if (error && errno != EWOULDBLOCK) err(EX_OSERR, "flock");
-	if (error) errx(EX_CANTCREAT, "%s: lock held by other process", path);
-
-	rewind(saveFile);
-	ringLoad(saveFile);
-
-	error = ftruncate(fileno(saveFile), 0);
-	if (error) err(EX_IOERR, "ftruncate");
-
-	atexit(saveExit);
+static volatile sig_atomic_t signals[NSIG];
+static void signalHandler(int signal) {
+	signals[signal] = 1;
 }
 
 int main(int argc, char *argv[]) {
@@ -194,16 +216,17 @@ int main(int argc, char *argv[]) {
 	ringAlloc(ring);
 	if (save) saveLoad(save);
 
-	FILE *cert = fopen(certPath, "r");
-	if (!cert) err(EX_NOINPUT, "%s", certPath);
-	FILE *priv = fopen(privPath, "r");
-	if (!priv) err(EX_NOINPUT, "%s", privPath);
+	int certDir, privDir;
+	const char *certFile = openParent(&certDir, certPath);
+	const char *privFile = openParent(&privDir, privPath);
+	FILE *cert = fopenat(certDir, certFile);
+	FILE *priv = fopenat(privDir, privFile);
 	listenConfig(cert, priv);
+	fclose(cert);
+	fclose(priv);
 
 	int bind[8];
-	listenConfig(certPath, privPath);
 	size_t binds = listenBind(bind, 8, bindHost, bindPort);
-
 	int server = serverConnect(insecure, host, port);
 
 #ifdef __FreeBSD__
@@ -211,13 +234,15 @@ int main(int argc, char *argv[]) {
 	if (error) err(EX_OSERR, "cap_enter");
 
 	cap_rights_t fileRights, sockRights, bindRights;
-	cap_rights_init(&fileRights, CAP_FSTAT, CAP_PREAD);
+	cap_rights_init(&fileRights, CAP_FCNTL, CAP_FSTAT, CAP_LOOKUP, CAP_READ);
 	cap_rights_init(&sockRights, CAP_EVENT, CAP_RECV, CAP_SEND, CAP_SETSOCKOPT);
 	cap_rights_init(&bindRights, CAP_LISTEN, CAP_ACCEPT);
 	cap_rights_merge(&bindRights, &sockRights);
 
-	cap_rights_limit(fileno(cert), &fileRights);
-	cap_rights_limit(fileno(priv), &fileRights);
+	error = cap_rights_limit(certDir, &fileRights);
+	if (error) err(EX_OSERR, "cap_rights_limit");
+	error = cap_rights_limit(privDir, &fileRights);
+	if (error) err(EX_OSERR, "cap_rights_limit");
 	for (size_t i = 0; i < binds; ++i) {
 		error = cap_rights_limit(bind[i], &bindRights);
 		if (error) err(EX_OSERR, "cap_rights_limit");
@@ -257,7 +282,11 @@ int main(int argc, char *argv[]) {
 			signals[SIGINFO] = 0;
 		}
 		if (signals[SIGUSR1]) {
+			cert = fopenat(certDir, certFile);
+			priv = fopenat(privDir, privFile);
 			listenConfig(cert, priv);
+			fclose(cert);
+			fclose(priv);
 			signals[SIGUSR1] = 0;
 		}
 
diff --git a/listen.c b/listen.c
index 9fc2443..f943ff2 100644
--- a/listen.c
+++ b/listen.c
@@ -29,7 +29,7 @@
 
 static struct tls *server;
 
-static byte *reread(size_t *len, FILE *file) {
+static byte *readFile(size_t *len, FILE *file) {
 	struct stat stat;
 	int error = fstat(fileno(file), &stat);
 	if (error) err(EX_IOERR, "fstat");
@@ -37,8 +37,6 @@ static byte *reread(size_t *len, FILE *file) {
 	byte *buf = malloc(stat.st_size);
 	if (!buf) err(EX_OSERR, "malloc");
 
-	fpurge(file);
-	rewind(file);
 	*len = fread(buf, 1, stat.st_size, file);
 	if (ferror(file)) err(EX_IOERR, "fread");
 
@@ -54,14 +52,14 @@ void listenConfig(FILE *cert, FILE *priv) {
 	if (!config) errx(EX_SOFTWARE, "tls_config_new");
 
 	size_t len;
-	byte *buf = reread(&len, cert);
+	byte *buf = readFile(&len, cert);
 	int error = tls_config_set_cert_mem(config, buf, len);
 	if (error) {
 		errx(EX_CONFIG, "tls_config_set_cert_mem: %s", tls_config_error(config));
 	}
 	free(buf);
 
-	buf = reread(&len, priv);
+	buf = readFile(&len, priv);
 	error = tls_config_set_key_mem(config, buf, len);
 	if (error) {
 		errx(EX_CONFIG, "tls_config_set_key_mem: %s", tls_config_error(config));