mirror of https://github.com/omar-polo/gmid.git
refactoring: imsg everywhere
use imsg to handle ALL kinds of IPC in gmid. This simplifies and shorten the code, and makes everything more uniform too.
This commit is contained in:
parent
1fbac5ba7c
commit
bc99d868bc
333
ex.c
333
ex.c
|
@ -27,199 +27,14 @@
|
|||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
int
|
||||
send_string(int fd, const char *str)
|
||||
{
|
||||
ssize_t len;
|
||||
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*);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
struct cgireq req;
|
||||
struct iri iri;
|
||||
int fd;
|
||||
|
||||
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, ¬before)
|
||||
|| !recv_time(fd, ¬after)
|
||||
|| !recv_vhost(fd, &vhost)) {
|
||||
if (errno == EINTR) {
|
||||
event_loopbreak();
|
||||
return;
|
||||
}
|
||||
fatal("failure in handling fork request: %s", strerror(errno));
|
||||
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);
|
||||
event_loopbreak();
|
||||
}
|
||||
|
||||
free_recvd_iri(&iri);
|
||||
free(spath);
|
||||
free(relpath);
|
||||
free(addr);
|
||||
free(ruser);
|
||||
free(cissuer);
|
||||
free(chash);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
75
gmid.c
75
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;
|
||||
|
||||
|
|
51
gmid.h
51
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
|
||||
|
|
66
log.c
66
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;
|
||||
event_loopbreak();
|
||||
}
|
||||
|
||||
if ((n = imsg_read(ibuf)) == -1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
return;
|
||||
err(1, "imsg_read");
|
||||
}
|
||||
if (n == 0)
|
||||
errx(1, "connection lost?");
|
||||
static void
|
||||
handle_imsg_log(struct imsgbuf *ibuf, struct imsg *imsg, size_t datalen)
|
||||
{
|
||||
char *msg;
|
||||
|
||||
for (;;) {
|
||||
if ((n = imsg_get(ibuf, &imsg)) == -1)
|
||||
err(1, "read error");
|
||||
if (n == 0)
|
||||
return;
|
||||
msg = imsg->data;
|
||||
msg[datalen-1] = '\0';
|
||||
|
||||
datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
|
||||
msg = imsg.data;
|
||||
msg[datalen-1] = '\0';
|
||||
if (conf.foreground)
|
||||
fprintf(stderr, "%s\n", msg);
|
||||
else
|
||||
syslog(LOG_DAEMON, "%s", msg);
|
||||
}
|
||||
|
||||
/* ignore imsg.hdr.type for now */
|
||||
if (conf.foreground)
|
||||
fprintf(stderr, "%s\n", msg);
|
||||
else
|
||||
syslog(LOG_DAEMON, "%s", msg);
|
||||
|
||||
imsg_free(&imsg);
|
||||
}
|
||||
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)
|
||||
|
|
|
@ -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;
|
||||
|
|
144
server.c
144
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));
|
||||
|
||||
memcpy(req.buf, c->req, sizeof(req.buf));
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
if ((c->pfd = recv_fd(exfd)) == -1) {
|
||||
start_reply(c, TEMP_FAILURE, "internal server error");
|
||||
return;
|
||||
}
|
||||
|
||||
reschedule_read(c->pfd, c, &handle_cgi_reply);
|
||||
return;
|
||||
|
||||
err:
|
||||
/* fatal("cannot talk to the executor process: %s", strerror(errno)); */
|
||||
fatal("cannot talk to the executor process");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_sighup(int fd, short ev, void *d)
|
||||
struct client *
|
||||
client_by_id(int id)
|
||||
{
|
||||
(void)fd;
|
||||
(void)ev;
|
||||
if ((size_t)id > sizeof(clients)/sizeof(clients[0]))
|
||||
fatal("in client_by_id: invalid id %d", id);
|
||||
return &clients[id];
|
||||
}
|
||||
|
||||
static void
|
||||
handle_imsg_cgi_res(struct imsgbuf *ibuf, struct imsg *imsg, size_t len)
|
||||
{
|
||||
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);
|
||||
|
|
48
utils.c
48
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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue