aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ex.c337
-rw-r--r--gmid.c75
-rw-r--r--gmid.h51
-rw-r--r--log.c72
-rw-r--r--regress/puny-test.c2
-rw-r--r--server.c140
-rw-r--r--utils.c48
7 files changed, 323 insertions, 402 deletions
diff --git a/ex.c b/ex.c
index 47eed0b..6817024 100644
--- a/ex.c
+++ b/ex.c
@@ -27,199 +27,14 @@
#include <stdarg.h>
#include <string.h>
-int
-send_string(int fd, const char *str)
-{
- ssize_t len;
-
- if (str == NULL)
- len = 0;
- else
- len = strlen(str);
-
- if (write(fd, &len, sizeof(len)) != sizeof(len))
- return 0;
-
- if (len != 0)
- if (write(fd, str, len) != len)
- return 0;
-
- return 1;
-}
-
-int
-recv_string(int fd, char **ret)
-{
- ssize_t len;
-
- if (read(fd, &len, sizeof(len)) != sizeof(len))
- return 0;
-
- if (len == 0) {
- *ret = NULL;
- return 1;
- }
-
- if ((*ret = calloc(1, len+1)) == NULL)
- return 0;
-
- if (read(fd, *ret, len) != len)
- return 0;
- return 1;
-}
-
-int
-send_iri(int fd, struct iri *i)
-{
- return send_string(fd, i->schema)
- && send_string(fd, i->host)
- && send_string(fd, i->port)
- && send_string(fd, i->path)
- && send_string(fd, i->query);
-}
+static void handle_imsg_cgi_req(struct imsgbuf*, struct imsg*, size_t);
+static void handle_imsg_quit(struct imsgbuf*, struct imsg*, size_t);
+static void handle_dispatch_imsg(int, short, void*);
-int
-recv_iri(int fd, struct iri *i)
-{
- memset(i, 0, sizeof(*i));
-
- if (!recv_string(fd, &i->schema)
- || !recv_string(fd, &i->host)
- || !recv_string(fd, &i->port)
- || !recv_string(fd, &i->path)
- || !recv_string(fd, &i->query))
- return 0;
-
- return 1;
-}
-
-void
-free_recvd_iri(struct iri *i)
-{
- free(i->schema);
- free(i->host);
- free(i->port);
- free(i->path);
- free(i->query);
-}
-
-int
-send_vhost(int fd, struct vhost *vhost)
-{
- ssize_t n;
-
- if (vhost < hosts || vhost > hosts + HOSTSLEN)
- return 0;
-
- n = vhost - hosts;
- return write(fd, &n, sizeof(n)) == sizeof(n);
-}
-
-int
-recv_vhost(int fd, struct vhost **vhost)
-{
- ssize_t n;
-
- if (read(fd, &n, sizeof(n)) != sizeof(n))
- return 0;
-
- if (n < 0 || n > HOSTSLEN)
- return 0;
-
- *vhost = &hosts[n];
- if ((*vhost)->domain == NULL)
- return 0;
- return 1;
-}
-
-int
-send_time(int fd, time_t t)
-{
- return write(fd, &t, sizeof(t)) == sizeof(t);
-}
-
-int
-recv_time(int fd, time_t *t)
-{
- return read(fd, t, sizeof(*t)) == sizeof(*t);
-}
-
-/* send d though fd. see /usr/src/usr.sbin/syslogd/privsep_fdpass.c
- * for an example */
-int
-send_fd(int fd, int d)
-{
- struct msghdr msg;
- union {
- struct cmsghdr hdr;
- unsigned char buf[CMSG_SPACE(sizeof(int))];
- } cmsgbuf;
- struct cmsghdr *cmsg;
- struct iovec vec;
- int result = 1;
- ssize_t n;
-
- memset(&msg, 0, sizeof(msg));
-
- if (d >= 0) {
- msg.msg_control = &cmsgbuf.buf;
- msg.msg_controllen = sizeof(cmsgbuf.buf);
- cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_len = CMSG_LEN(sizeof(int));
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- *(int*)CMSG_DATA(cmsg) = d;
- } else
- result = 0;
-
- vec.iov_base = &result;
- vec.iov_len = sizeof(int);
- msg.msg_iov = &vec;
- msg.msg_iovlen = 1;
-
- if ((n = sendmsg(fd, &msg, 0)) == -1 || n != sizeof(int)) {
- log_err(NULL, "sendmsg: got %zu but wanted %zu: (errno) %s",
- n, sizeof(int), strerror(errno));
- return 0;
- }
- return 1;
-}
-
-/* receive a descriptor via fd */
-int
-recv_fd(int fd)
-{
- struct msghdr msg;
- union {
- struct cmsghdr hdr;
- char buf[CMSG_SPACE(sizeof(int))];
- } cmsgbuf;
- struct cmsghdr *cmsg;
- struct iovec vec;
- ssize_t n;
- int result;
-
- memset(&msg, 0, sizeof(msg));
- vec.iov_base = &result;
- vec.iov_len = sizeof(int);
- msg.msg_iov = &vec;
- msg.msg_iovlen = 1;
- msg.msg_control = &cmsgbuf.buf;
- msg.msg_controllen = sizeof(cmsgbuf.buf);
-
- if ((n = recvmsg(fd, &msg, 0)) != sizeof(int)) {
- log_err(NULL, "read %zu bytes bu wanted %zu\n", n, sizeof(int));
- return -1;
- }
-
- if (result) {
- cmsg = CMSG_FIRSTHDR(&msg);
- if (cmsg == NULL || cmsg->cmsg_type != SCM_RIGHTS)
- return -1;
- return (*(int *)CMSG_DATA(cmsg));
- } else
- return -1;
-}
+static imsg_handlerfn *handlers[] = {
+ [IMSG_CGI_REQ] = handle_imsg_cgi_req,
+ [IMSG_QUIT] = handle_imsg_quit,
+};
static inline void
safe_setenv(const char *name, const char *val)
@@ -299,10 +114,7 @@ setenv_time(const char *var, time_t t)
/* fd or -1 on error */
static int
-launch_cgi(struct iri *iri, const char *spath, char *relpath,
- const char *addr, const char *ruser, const char *cissuer,
- const char *chash, time_t notbefore, time_t notafter,
- struct vhost *vhost)
+launch_cgi(struct iri *iri, struct cgireq *req, struct vhost *vhost)
{
int p[2]; /* read end, write end */
@@ -322,38 +134,38 @@ launch_cgi(struct iri *iri, const char *spath, char *relpath,
if (dup2(p[1], 1) == -1)
goto childerr;
- ex = xasprintf("%s/%s", vhost->dir, spath);
+ ex = xasprintf("%s/%s", vhost->dir, req->spath);
serialize_iri(iri, iribuf, sizeof(iribuf));
safe_setenv("GATEWAY_INTERFACE", "CGI/1.1");
safe_setenv("GEMINI_DOCUMENT_ROOT", vhost->dir);
safe_setenv("GEMINI_SCRIPT_FILENAME",
- xasprintf("%s/%s", vhost->dir, spath));
+ xasprintf("%s/%s", vhost->dir, req->spath));
safe_setenv("GEMINI_URL", iribuf);
strlcpy(path, "/", sizeof(path));
- strlcat(path, spath, sizeof(path));
+ strlcat(path, req->spath, sizeof(path));
safe_setenv("GEMINI_URL_PATH", path);
- if (relpath != NULL) {
+ if (*req->relpath != '\0') {
strlcpy(path, "/", sizeof(path));
- strlcat(path, relpath, sizeof(path));
+ strlcat(path, req->relpath, sizeof(path));
safe_setenv("PATH_INFO", path);
strlcpy(path, vhost->dir, sizeof(path));
strlcat(path, "/", sizeof(path));
- strlcat(path, relpath, sizeof(path));
+ strlcat(path, req->relpath, sizeof(path));
safe_setenv("PATH_TRANSLATED", path);
}
safe_setenv("QUERY_STRING", iri->query);
- safe_setenv("REMOTE_ADDR", addr);
- safe_setenv("REMOTE_HOST", addr);
+ safe_setenv("REMOTE_ADDR", req->addr);
+ safe_setenv("REMOTE_HOST", req->addr);
safe_setenv("REQUEST_METHOD", "");
strlcpy(path, "/", sizeof(path));
- strlcat(path, spath, sizeof(path));
+ strlcat(path, req->spath, sizeof(path));
safe_setenv("SCRIPT_NAME", path);
safe_setenv("SERVER_NAME", iri->host);
@@ -364,16 +176,16 @@ launch_cgi(struct iri *iri, const char *spath, char *relpath,
safe_setenv("SERVER_PROTOCOL", "GEMINI");
safe_setenv("SERVER_SOFTWARE", "gmid/1.5");
- if (ruser != NULL)
+ if (*req->subject != '\0')
safe_setenv("AUTH_TYPE", "Certificate");
else
safe_setenv("AUTH_TYPE", "");
- safe_setenv("REMOTE_USER", ruser);
- safe_setenv("TLS_CLIENT_ISSUER", cissuer);
- safe_setenv("TLS_CLIENT_HASH", chash);
- setenv_time("TLS_CLIENT_NOT_AFTER", notafter);
- setenv_time("TLS_CLIENT_NOT_BEFORE", notbefore);
+ safe_setenv("REMOTE_USER", req->subject);
+ safe_setenv("TLS_CLIENT_ISSUER", req->issuer);
+ safe_setenv("TLS_CLIENT_HASH", req->hash);
+ setenv_time("TLS_CLIENT_NOT_AFTER", req->notafter);
+ setenv_time("TLS_CLIENT_NOT_BEFORE", req->notbefore);
strlcpy(path, ex, sizeof(path));
@@ -383,7 +195,7 @@ launch_cgi(struct iri *iri, const char *spath, char *relpath,
goto childerr;
}
- do_exec(ex, spath, iri->query);
+ do_exec(ex, req->spath, iri->query);
goto childerr;
}
@@ -399,52 +211,67 @@ childerr:
}
static void
-handle_fork_req(int fd, short ev, void *data)
+handle_imsg_cgi_req(struct imsgbuf *ibuf, struct imsg *imsg, size_t datalen)
{
- char *spath, *relpath, *addr, *ruser, *cissuer, *chash;
- struct vhost *vhost;
- struct iri iri;
- time_t notbefore, notafter;
- int d;
-
- if (!recv_iri(fd, &iri)
- || !recv_string(fd, &spath)
- || !recv_string(fd, &relpath)
- || !recv_string(fd, &addr)
- || !recv_string(fd, &ruser)
- || !recv_string(fd, &cissuer)
- || !recv_string(fd, &chash)
- || !recv_time(fd, &notbefore)
- || !recv_time(fd, &notafter)
- || !recv_vhost(fd, &vhost)) {
- if (errno == EINTR) {
- event_loopbreak();
- return;
- }
- fatal("failure in handling fork request: %s", strerror(errno));
+ struct cgireq req;
+ struct iri iri;
+ int fd;
+
+ if (datalen != sizeof(req))
+ abort();
+
+ memcpy(&req, imsg->data, datalen);
+
+ iri.schema = req.iri_schema_off + req.buf;
+ iri.host = req.iri_host_off + req.buf;
+ iri.port = req.iri_port_off + req.buf;
+ iri.path = req.iri_path_off + req.buf;
+ iri.query = req.iri_query_off + req.buf;
+ iri.fragment = req.iri_fragment_off + req.buf;
+
+ /* patch the query, otherwise do_exec will always pass "" as
+ * first argument to the script. */
+ if (*iri.query == '\0')
+ iri.query = NULL;
+
+ if (req.host_off > HOSTSLEN || hosts[req.host_off].domain == NULL)
+ abort();
+
+ fd = launch_cgi(&iri, &req, &hosts[req.host_off]);
+ imsg_compose(ibuf, IMSG_CGI_RES, imsg->hdr.peerid, 0, fd, NULL, 0);
+ imsg_flush(ibuf);
+}
+
+static void
+handle_imsg_quit(struct imsgbuf *ibuf, struct imsg *imsg, size_t datalen)
+{
+ int i;
+
+ (void)ibuf;
+ (void)imsg;
+ (void)datalen;
+
+ for (i = 0; i < conf.prefork; ++i) {
+ imsg_compose(&servibuf[i], IMSG_QUIT, 0, 0, -1, NULL, 0);
+ imsg_flush(&exibuf);
+ close(servibuf[i].fd);
}
- d = launch_cgi(&iri, spath, relpath, addr, ruser, cissuer, chash,
- notbefore, notafter, vhost);
- if (!send_fd(fd, d))
- fatal("failure in sending the fd to the server: %s",
- strerror(errno));
- close(d);
-
- free_recvd_iri(&iri);
- free(spath);
- free(relpath);
- free(addr);
- free(ruser);
- free(cissuer);
- free(chash);
+ event_loopbreak();
+}
+
+static void
+handle_dispatch_imsg(int fd, short ev, void *d)
+{
+ struct imsgbuf *ibuf = d;
+ dispatch_imsg(ibuf, handlers, sizeof(handlers));
}
int
-executor_main(void)
+executor_main(struct imsgbuf *ibuf)
{
struct vhost *vhost;
- struct event evs[PROC_MAX];
+ struct event evs[PROC_MAX], imsgev;
int i;
#ifdef __OpenBSD__
@@ -462,9 +289,15 @@ executor_main(void)
event_init();
+ if (ibuf != NULL) {
+ event_set(&imsgev, ibuf->fd, EV_READ | EV_PERSIST,
+ handle_dispatch_imsg, ibuf);
+ event_add(&imsgev, NULL);
+ }
+
for (i = 0; i < conf.prefork; ++i) {
- event_set(&evs[i], servpipes[i], EV_READ | EV_PERSIST,
- handle_fork_req, NULL);
+ event_set(&evs[i], servibuf[i].fd, EV_READ | EV_PERSIST,
+ handle_dispatch_imsg, &servibuf[i]);
event_add(&evs[i], NULL);
}
diff --git a/gmid.c b/gmid.c
index 823299b..0714df4 100644
--- a/gmid.c
+++ b/gmid.c
@@ -25,13 +25,11 @@
#include <signal.h>
#include <string.h>
-volatile sig_atomic_t hupped;
-
struct vhost hosts[HOSTSLEN];
-int exfd, logfd, sock4, sock6, servpipes[PROC_MAX];
+int sock4, sock6;
-struct imsgbuf logpibuf, logcibuf;
+struct imsgbuf logibuf, exibuf, servibuf[PROC_MAX];
const char *config_path, *certs_dir, *hostname;
@@ -40,14 +38,6 @@ struct conf conf;
struct tls_config *tlsconf;
struct tls *ctx;
-void
-sig_handler(int sig)
-{
- (void)sig;
-
- hupped = sig == SIGHUP;
-}
-
/* XXX: create recursively */
void
mkdirs(const char *path)
@@ -196,13 +186,12 @@ setup_tls(void)
}
static int
-listener_main(void)
+listener_main(struct imsgbuf *ibuf)
{
drop_priv();
- unblock_signals();
load_default_mime(&conf.mime);
load_vhosts();
- loop(ctx, sock4, sock6);
+ loop(ctx, sock4, sock6, ibuf);
return 0;
}
@@ -320,22 +309,21 @@ logger_init(void)
case -1:
err(1, "fork");
case 0:
- logfd = p[1];
+ signal(SIGHUP, SIG_IGN);
close(p[0]);
setproctitle("logger");
- imsg_init(&logcibuf, p[1]);
+ imsg_init(&logibuf, p[1]);
drop_priv();
- _exit(logger_main(p[1], &logcibuf));
+ _exit(logger_main(p[1], &logibuf));
default:
- logfd = p[0];
close(p[1]);
- imsg_init(&logpibuf, p[0]);
+ imsg_init(&logibuf, p[0]);
return;
}
}
static int
-serve(int argc, char **argv)
+serve(int argc, char **argv, struct imsgbuf *ibuf)
{
char path[PATH_MAX];
int i, p[2];
@@ -380,19 +368,18 @@ serve(int argc, char **argv)
fatal("fork: %s", strerror(errno));
case 0: /* child */
close(p[0]);
- exfd = p[1];
+ imsg_init(&exibuf, p[1]);
setproctitle("server");
- _exit(listener_main());
+ _exit(listener_main(&exibuf));
default:
- servpipes[i] = p[0];
close(p[1]);
+ imsg_init(&servibuf[i], p[0]);
}
}
setproctitle("executor");
drop_priv();
- unblock_signals();
- _exit(executor_main());
+ _exit(executor_main(ibuf));
}
int
@@ -480,12 +467,6 @@ main(int argc, char **argv)
signal(SIGPIPE, SIG_IGN);
signal(SIGCHLD, SIG_IGN);
-#ifdef SIGINFO
- signal(SIGINFO, sig_handler);
-#endif
- signal(SIGUSR2, sig_handler);
- signal(SIGHUP, sig_handler);
-
if (!conf.foreground && !configless) {
if (daemon(1, 1) == -1)
err(1, "daemon");
@@ -501,25 +482,43 @@ main(int argc, char **argv)
if (conf.ipv6)
sock6 = make_socket(conf.port, AF_INET6);
- if (configless)
- return serve(argc, argv);
+ if (configless) {
+ serve(argc, argv, NULL);
+ imsg_compose(&logibuf, IMSG_QUIT, 0, 0, -1, NULL, 0);
+ imsg_flush(&logibuf);
+ return 0;
+ }
/* wait a sighup and reload the daemon */
for (;;) {
- block_signals();
+ struct imsgbuf exibuf;
+ int p[2];
+
+ if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC,
+ PF_UNSPEC, p) == -1)
+ fatal("socketpair: %s", strerror(errno));
- hupped = 0;
switch (fork()) {
case -1:
fatal("fork: %s", strerror(errno));
case 0:
- return serve(argc, argv);
+ signal(SIGHUP, SIG_IGN);
+ close(p[0]);
+ imsg_init(&exibuf, p[1]);
+ _exit(serve(argc, argv, &exibuf));
}
+ close(p[1]);
+ imsg_init(&exibuf, p[0]);
+
wait_sighup();
- unblock_signals();
log_info(NULL, "reloading configuration %s", config_path);
+ /* close the executor (it'll close the servers too) */
+ imsg_compose(&exibuf, IMSG_QUIT, 0, 0, -1, NULL, 0);
+ imsg_flush(&exibuf);
+ close(p[0]);
+
old_ipv6 = conf.ipv6;
old_port = conf.port;
diff --git a/gmid.h b/gmid.h
index b858ebc..dad7b4c 100644
--- a/gmid.h
+++ b/gmid.h
@@ -26,6 +26,8 @@
#include <netinet/in.h>
#include <dirent.h>
+#include <limits.h>
+#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
@@ -116,11 +118,8 @@ struct conf {
extern const char *config_path;
extern struct conf conf;
-extern int exfd, logfd;
-extern struct imsgbuf logpibuf, logcibuf;
-
-extern volatile sig_atomic_t hupped;
+extern struct imsgbuf logibuf, exibuf, servibuf[PROC_MAX];
extern int servpipes[PROC_MAX];
@@ -142,6 +141,8 @@ struct parser {
struct client;
+typedef void (imsg_handlerfn)(struct imsgbuf*, struct imsg*, size_t);
+
typedef void (*statefn)(int, short, void*);
/*
@@ -169,6 +170,7 @@ typedef void (*statefn)(int, short, void*);
* send_file -> close_conn
*/
struct client {
+ int id;
struct tls *ctx;
char req[GEMINI_URL_LEN];
struct iri iri;
@@ -181,7 +183,33 @@ struct client {
char sbuf[1024];
ssize_t len, off;
struct sockaddr_storage addr;
- struct vhost *host; /* host she's talking to */
+ struct vhost *host; /* host they're talking to */
+};
+
+struct cgireq {
+ char buf[GEMINI_URL_LEN];
+
+ size_t iri_schema_off;
+ size_t iri_host_off;
+ size_t iri_port_off;
+ size_t iri_path_off;
+ size_t iri_query_off;
+ size_t iri_fragment_off;
+ int iri_portno;
+
+ char spath[PATH_MAX+1];
+ char relpath[PATH_MAX+1];
+ char addr[NI_MAXHOST+1];
+
+ /* AFAIK there isn't an upper limit for these two fields. */
+ char subject[64+1];
+ char issuer[64+1];
+
+ char hash[128+1];
+ time_t notbefore;
+ time_t notafter;
+
+ size_t host_off;
};
enum {
@@ -191,8 +219,14 @@ enum {
FILE_MISSING,
};
+enum imsg_type {
+ IMSG_CGI_REQ,
+ IMSG_CGI_RES,
+ IMSG_LOG,
+ IMSG_QUIT,
+};
+
/* gmid.c */
-void sig_handler(int);
void mkdirs(const char*);
char *data_dir(void);
void load_local_cert(const char*, const char*);
@@ -243,7 +277,7 @@ int vhost_strip(struct vhost*, const char*);
X509_STORE *vhost_require_ca(struct vhost*, const char*);
int vhost_disable_log(struct vhost*, const char*);
void mark_nonblock(int);
-void loop(struct tls*, int, int);
+void loop(struct tls*, int, int, struct imsgbuf*);
/* ex.c */
int send_string(int, const char*);
@@ -257,7 +291,7 @@ int send_time(int, time_t);
int recv_time(int, time_t*);
int send_fd(int, int);
int recv_fd(int);
-int executor_main(void);
+int executor_main(struct imsgbuf*);
/* sandbox.c */
void sandbox(void);
@@ -286,5 +320,6 @@ char *xstrdup(const char*);
void gen_certificate(const char*, const char*, const char*);
X509_STORE *load_ca(const char*);
int validate_against_ca(X509_STORE*, const uint8_t*, size_t);
+void dispatch_imsg(struct imsgbuf*, imsg_handlerfn**, size_t);
#endif
diff --git a/log.c b/log.c
index 767d823..b66aa19 100644
--- a/log.c
+++ b/log.c
@@ -28,9 +28,16 @@
#include <string.h>
#include <syslog.h>
-static struct event inlog;
+static struct event imsgev;
-static void handle_log(int, short, void*);
+static void handle_imsg_quit(struct imsgbuf*, struct imsg*, size_t);
+static void handle_imsg_log(struct imsgbuf*, struct imsg*, size_t);
+static void handle_dispatch_imsg(int, short, void*);
+
+static imsg_handlerfn *handlers[] = {
+ [IMSG_QUIT] = handle_imsg_quit,
+ [IMSG_LOG] = handle_imsg_log,
+};
void
fatal(const char *fmt, ...)
@@ -71,9 +78,9 @@ should_log(int priority)
static inline void
send_log(const char *msg, size_t len)
{
- imsg_compose(&logpibuf, 0, 0, 0, -1, msg, len);
+ imsg_compose(&logibuf, IMSG_LOG, 0, 0, -1, msg, len);
/* XXX: use event_once() */
- imsg_flush(&logpibuf);
+ imsg_flush(&logibuf);
}
static inline void
@@ -229,39 +236,30 @@ log_request(struct client *c, char *meta, size_t l)
static void
-handle_log(int fd, short ev, void *d)
+handle_imsg_quit(struct imsgbuf *ibuf, struct imsg *imsg, size_t datalen)
{
- struct imsgbuf *ibuf = d;
- struct imsg imsg;
- ssize_t n, datalen;
- char *msg;
-
- if ((n = imsg_read(ibuf)) == -1) {
- if (errno == EAGAIN || errno == EWOULDBLOCK)
- return;
- err(1, "imsg_read");
- }
- if (n == 0)
- errx(1, "connection lost?");
-
- for (;;) {
- if ((n = imsg_get(ibuf, &imsg)) == -1)
- err(1, "read error");
- if (n == 0)
- return;
-
- datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
- msg = imsg.data;
- msg[datalen-1] = '\0';
-
- /* ignore imsg.hdr.type for now */
- if (conf.foreground)
- fprintf(stderr, "%s\n", msg);
- else
- syslog(LOG_DAEMON, "%s", msg);
+ event_loopbreak();
+}
- imsg_free(&imsg);
- }
+static void
+handle_imsg_log(struct imsgbuf *ibuf, struct imsg *imsg, size_t datalen)
+{
+ char *msg;
+
+ msg = imsg->data;
+ msg[datalen-1] = '\0';
+
+ if (conf.foreground)
+ fprintf(stderr, "%s\n", msg);
+ else
+ syslog(LOG_DAEMON, "%s", msg);
+}
+
+static void
+handle_dispatch_imsg(int fd, short ev, void *d)
+{
+ struct imsgbuf *ibuf = d;
+ dispatch_imsg(ibuf, handlers, sizeof(handlers));
}
int
@@ -269,8 +267,8 @@ logger_main(int fd, struct imsgbuf *ibuf)
{
event_init();
- event_set(&inlog, fd, EV_READ | EV_PERSIST, &handle_log, ibuf);
- event_add(&inlog, NULL);
+ event_set(&imsgev, fd, EV_READ | EV_PERSIST, &handle_dispatch_imsg, ibuf);
+ event_add(&imsgev, NULL);
#ifdef __OpenBSD__
if (pledge("stdio", NULL) == -1)
diff --git a/regress/puny-test.c b/regress/puny-test.c
index 1d69261..2397e9a 100644
--- a/regress/puny-test.c
+++ b/regress/puny-test.c
@@ -21,7 +21,7 @@
/* to make the linker happy */
struct conf conf;
-struct imsgbuf logpibuf, logcibuf;
+struct imsgbuf logibuf, servibuf[PROC_MAX];
struct suite {
const char *src;
diff --git a/server.c b/server.c
index bfb9dce..b059412 100644
--- a/server.c
+++ b/server.c
@@ -18,8 +18,6 @@
#include <sys/stat.h>
-#include <netdb.h>
-
#include <assert.h>
#include <errno.h>
#include <event.h>
@@ -28,12 +26,10 @@
#include <limits.h>
#include <string.h>
-struct server {
- struct client clients[MAX_USERS];
- struct tls *ctx;
-};
+static struct client clients[MAX_USERS];
+static struct tls *ctx;
-static struct event e4, e6, sighup, siginfo, sigusr2;
+static struct event e4, e6, imsgev, siginfo, sigusr2;
static int has_ipv6, has_siginfo;
int connected_clients;
@@ -65,7 +61,15 @@ static void handle_cgi_reply(int, short, void*);
static void handle_copy(int, short, void*);
static void close_conn(int, short, void*);
static void do_accept(int, short, void*);
-static void handle_sighup(int, short, void*);
+struct client *client_by_id(int);
+static void handle_imsg_cgi_res(struct imsgbuf*, struct imsg*, size_t);
+static void handle_imsg_quit(struct imsgbuf*, struct imsg*, size_t);
+static void handle_siginfo(int, short, void*);
+
+static imsg_handlerfn *handlers[] = {
+ [IMSG_QUIT] = handle_imsg_quit,
+ [IMSG_CGI_RES] = handle_imsg_cgi_res,
+};
static inline int
matches(const char *pattern, const char *path)
@@ -633,6 +637,8 @@ static void
start_cgi(const char *spath, const char *relpath, struct client *c)
{
char addr[NI_MAXHOST];
+ const char *t;
+ struct cgireq req;
int e;
e = getnameinfo((struct sockaddr*)&c->addr, sizeof(c->addr),
@@ -640,32 +646,41 @@ start_cgi(const char *spath, const char *relpath, struct client *c)
NULL, 0,
NI_NUMERICHOST);
if (e != 0)
- goto err;
+ fatal("getnameinfo failed");
- if (!send_iri(exfd, &c->iri)
- || !send_string(exfd, spath)
- || !send_string(exfd, relpath)
- || !send_string(exfd, addr)
- || !send_string(exfd, tls_peer_cert_subject(c->ctx))
- || !send_string(exfd, tls_peer_cert_issuer(c->ctx))
- || !send_string(exfd, tls_peer_cert_hash(c->ctx))
- || !send_time(exfd, tls_peer_cert_notbefore(c->ctx))
- || !send_time(exfd, tls_peer_cert_notafter(c->ctx))
- || !send_vhost(exfd, c->host))
- goto err;
+ memset(&req, 0, sizeof(req));
- close(c->pfd);
- if ((c->pfd = recv_fd(exfd)) == -1) {
- start_reply(c, TEMP_FAILURE, "internal server error");
- return;
- }
+ memcpy(req.buf, c->req, sizeof(req.buf));
- reschedule_read(c->pfd, c, &handle_cgi_reply);
- return;
+ req.iri_schema_off = c->iri.schema - c->req;
+ req.iri_host_off = c->iri.host - c->req;
+ req.iri_port_off = c->iri.port - c->req;
+ req.iri_path_off = c->iri.path - c->req;
+ req.iri_query_off = c->iri.query - c->req;
+ req.iri_fragment_off = c->iri.fragment - c->req;
-err:
- /* fatal("cannot talk to the executor process: %s", strerror(errno)); */
- fatal("cannot talk to the executor process");
+ req.iri_portno = c->iri.port_no;
+
+ strlcpy(req.spath, spath, sizeof(req.spath));
+ strlcpy(req.relpath, relpath, sizeof(req.relpath));
+ strlcpy(req.addr, addr, sizeof(req.addr));
+
+ if ((t = tls_peer_cert_subject(c->ctx)) != NULL)
+ strlcpy(req.subject, t, sizeof(req.subject));
+ if ((t = tls_peer_cert_issuer(c->ctx)) != NULL)
+ strlcpy(req.issuer, t, sizeof(req.issuer));
+ if ((t = tls_peer_cert_hash(c->ctx)) != NULL)
+ strlcpy(req.hash, t, sizeof(req.hash));
+
+ req.notbefore = tls_peer_cert_notbefore(c->ctx);
+ req.notafter = tls_peer_cert_notafter(c->ctx);
+
+ req.host_off = c->host - hosts;
+
+ imsg_compose(&exibuf, IMSG_CGI_REQ, c->id, 0, -1, &req, sizeof(req));
+ imsg_flush(&exibuf);
+
+ close(c->pfd);
}
static void
@@ -986,7 +1001,6 @@ static void
do_accept(int sock, short et, void *d)
{
struct client *c;
- struct server *s = d;
struct sockaddr_storage addr;
struct sockaddr *saddr;
socklen_t len;
@@ -994,7 +1008,6 @@ do_accept(int sock, short et, void *d)
(void)et;
-
saddr = (struct sockaddr*)&addr;
len = sizeof(addr);
if ((fd = accept(sock, saddr, &len)) == -1) {
@@ -1006,10 +1019,11 @@ do_accept(int sock, short et, void *d)
mark_nonblock(fd);
for (i = 0; i < MAX_USERS; ++i) {
- c = &s->clients[i];
+ c = &clients[i];
if (c->fd == -1) {
memset(c, 0, sizeof(*c));
- if (tls_accept_socket(s->ctx, &c->ctx, fd) == -1)
+ c->id = i;
+ if (tls_accept_socket(ctx, &c->ctx, fd) == -1)
break; /* goodbye fd! */
c->fd = fd;
@@ -1026,19 +1040,50 @@ do_accept(int sock, short et, void *d)
close(fd);
}
+struct client *
+client_by_id(int id)
+{
+ if ((size_t)id > sizeof(clients)/sizeof(clients[0]))
+ fatal("in client_by_id: invalid id %d", id);
+ return &clients[id];
+}
+
static void
-handle_sighup(int fd, short ev, void *d)
+handle_imsg_cgi_res(struct imsgbuf *ibuf, struct imsg *imsg, size_t len)
{
- (void)fd;
- (void)ev;
+ struct client *c;
+
+ c = client_by_id(imsg->hdr.peerid);
+
+ if ((c->pfd = imsg->fd) == -1)
+ start_reply(c, TEMP_FAILURE, "internal server error");
+ else
+ reschedule_read(c->pfd, c, &handle_cgi_reply);
+}
+
+static void
+handle_imsg_quit(struct imsgbuf *ibuf, struct imsg *imsg, size_t len)
+{
+ (void)imsg;
+ (void)len;
+
+ /* don't call event_loopbreak since we want to finish to
+ * handle the ongoing connections. */
event_del(&e4);
if (has_ipv6)
event_del(&e6);
if (has_siginfo)
signal_del(&siginfo);
+ event_del(&imsgev);
signal_del(&sigusr2);
- signal_del(&sighup);
+}
+
+static void
+handle_dispatch_imsg(int fd, short ev, void *d)
+{
+ struct imsgbuf *ibuf = d;
+ dispatch_imsg(ibuf, handlers, sizeof(handlers));
}
static void
@@ -1052,28 +1097,29 @@ handle_siginfo(int fd, short ev, void *d)
}
void
-loop(struct tls *ctx, int sock4, int sock6)
+loop(struct tls *ctx_, int sock4, int sock6, struct imsgbuf *ibuf)
{
- struct server server;
size_t i;
+ ctx = ctx_;
+
event_init();
- memset(&server, 0, sizeof(server));
+ memset(&clients, 0, sizeof(clients));
for (i = 0; i < MAX_USERS; ++i)
- server.clients[i].fd = -1;
+ clients[i].fd = -1;
- event_set(&e4, sock4, EV_READ | EV_PERSIST, &do_accept, &server);
+ event_set(&e4, sock4, EV_READ | EV_PERSIST, &do_accept, NULL);
event_add(&e4, NULL);
if (sock6 != -1) {
has_ipv6 = 1;
- event_set(&e6, sock6, EV_READ | EV_PERSIST, &do_accept, &server);
+ event_set(&e6, sock6, EV_READ | EV_PERSIST, &do_accept, NULL);
event_add(&e6, NULL);
}
- signal_set(&sighup, SIGHUP, &handle_sighup, NULL);
- signal_add(&sighup, NULL);
+ event_set(&imsgev, ibuf->fd, EV_READ | EV_PERSIST, handle_dispatch_imsg, ibuf);
+ event_add(&imsgev, NULL);
#ifdef SIGINFO
has_siginfo = 1;
@@ -1083,8 +1129,6 @@ loop(struct tls *ctx, int sock4, int sock6)
signal_set(&sigusr2, SIGUSR2, &handle_siginfo, NULL);
signal_add(&sigusr2, NULL);
- server.ctx = ctx;
-
sandbox();
event_dispatch();
_exit(0);
diff --git a/utils.c b/utils.c
index 50f57a1..5d831f1 100644
--- a/utils.c
+++ b/utils.c
@@ -24,24 +24,6 @@
#include <openssl/x509_vfy.h>
#include <openssl/x509v3.h>
-static sigset_t set;
-
-void
-block_signals(void)
-{
- sigset_t new;
-
- sigemptyset(&new);
- sigaddset(&new, SIGHUP);
- sigprocmask(SIG_BLOCK, &new, &set);
-}
-
-void
-unblock_signals(void)
-{
- sigprocmask(SIG_SETMASK, &set, NULL);
-}
-
int
starts_with(const char *str, const char *prefix)
{
@@ -248,3 +230,33 @@ end:
X509_STORE_CTX_free(ctx);
return ret;
}
+
+void
+dispatch_imsg(struct imsgbuf *ibuf, imsg_handlerfn **handlers, size_t size)
+{
+ struct imsg imsg;
+ size_t datalen, i;
+ ssize_t n;
+
+ if ((n = imsg_read(ibuf)) == -1) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ return;
+ _exit(1);
+ }
+
+ if (n == 0)
+ _exit(1);
+
+ for (;;) {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ _exit(1);
+ if (n == 0)
+ return;
+ datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
+ i = imsg.hdr.type;
+ if (i > (size / sizeof(imsg_handlerfn*)) || handlers[i] == NULL)
+ abort();
+ handlers[i](ibuf, &imsg, datalen);
+ imsg_free(&imsg);
+ }
+}