geomyidae

A small C-based gopherd. (gopher://bitreich.org/1/scm/geomyidae)
git clone git://r-36.net/geomyidae
Log | Files | Refs | README | LICENSE

commit 07240d76fd8e1d0a67c49bf7e123bb508613e691
parent 4500d3596d7b166ad1e832adeefc6be3da685b09
Author: Christoph Lohmann <20h@r-36.net>
Date:   Sun,  7 Jun 2020 18:49:28 +0200

Add tls support to geomyidae.

Diffstat:
Makefile | 2+-
handlr.c | 11+++++++----
main.c | 168++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
3 files changed, 149 insertions(+), 32 deletions(-)

diff --git a/Makefile b/Makefile @@ -11,7 +11,7 @@ MANDIR = ${PREFIX}/share/man/man8 CFLAGS = -O2 -Wall GEOM_CFLAGS = -D_DEFAULT_SOURCE -I. -I/usr/include ${CFLAGS} -GEOM_LDFLAGS = -L/usr/lib -L. ${LDFLAGS} +GEOM_LDFLAGS = -L/usr/lib -L. -ltls ${LDFLAGS} SRC = main.c ind.c handlr.c OBJ = ${SRC:.c=.o} diff --git a/handlr.c b/handlr.c @@ -16,6 +16,8 @@ #include <sys/stat.h> #include <dirent.h> #include <sys/wait.h> +#include <errno.h> + #include "ind.h" #include "arg.h" @@ -205,11 +207,11 @@ handledcgi(int sock, char *file, char *port, char *base, char *args, if (args == NULL) args = ""; - dup2(sock, 0); - dup2(sock, 2); + while (dup2(sock, 0) < 0 && errno == EINTR); + while (dup2(sock, 2) < 0 && errno == EINTR); switch (fork()) { case 0: - dup2(outpipe[1], 1); + while(dup2(outpipe[1], 1) < 0 && errno == EINTR); close(outpipe[0]); if (path != NULL) { if (chdir(path) < 0) @@ -223,11 +225,12 @@ handledcgi(int sock, char *file, char *port, char *base, char *args, perror("execl"); _exit(1); } + break; case -1: perror("fork"); break; default: - dup2(sock, 1); + while(dup2(sock, 1) < 0 && errno == EINTR); close(outpipe[1]); if (!(fp = fdopen(outpipe[0], "r"))) { diff --git a/main.c b/main.c @@ -25,6 +25,7 @@ #include <arpa/inet.h> #include <sys/select.h> #include <sys/time.h> +#include <tls.h> #include "ind.h" #include "handlr.h" @@ -116,34 +117,22 @@ logentry(char *host, char *port, char *qry, char *status) } void -handlerequest(int sock, char *base, char *ohost, char *port, char *clienth, - char *clientp, int nocgi) +handlerequest(int sock, char *req, int rlen, char *base, char *ohost, + char *port, char *clienth, char *clientp, int nocgi) { struct stat dir; char recvc[1025], recvb[1025], path[1025], *args = NULL, *sear, *c; - int len = 0, fd, i, retl, maxrecv; + int len = 0, fd, i, maxrecv; filetype *type; memset(&dir, 0, sizeof(dir)); memset(recvb, 0, sizeof(recvb)); memset(recvc, 0, sizeof(recvc)); - maxrecv = sizeof(recvb); - /* - * Force at least one byte per packet. Limit, so the server - * cannot be put into DoS via zero-length packets. - */ - do { - retl = recv(sock, recvb+len, sizeof(recvb)-1-len, 0); - if (retl <= 0) { - if (retl < 0) - perror("recv"); - break; - } - len += retl; - } while (recvb[len-1] != '\n' && --maxrecv > 0); - if (len <= 0) + maxrecv = sizeof(recvb) - 1; + if (rlen > maxrecv || rlen < 0) return; + memcpy(recvb, req, rlen); c = strchr(recvb, '\r'); if (c) @@ -174,7 +163,7 @@ handlerequest(int sock, char *base, char *ohost, char *port, char *clienth, } } - memmove(recvc, recvb, len+1); + memmove(recvc, recvb, rlen+1); if (!strncmp(recvb, "URL:", 4)) { len = snprintf(path, sizeof(path), htredir, @@ -409,6 +398,7 @@ void usage(void) { dprintf(2, "usage: %s [-46cden] [-l logfile] " + "[-t keyfile certfile] " "[-v loglvl] [-b base] [-p port] [-o sport] " "[-u user] [-g group] [-h host] [-i interface ...]\n", argv0); @@ -423,13 +413,18 @@ main(int argc, char *argv[]) socklen_t cltlen; int sock, dofork = 1, inetf = AF_UNSPEC, usechroot = 0, nocgi = 0, errno_save, nbindips = 0, i, j, - nlfdret, *lfdret, listfd, maxlfd; + nlfdret, *lfdret, listfd, maxlfd, dotls = 0, istls = 0, + shuflen, wlen, shufpos, tlspipe[2], maxrecv, retl, + rlen = 0; fd_set rfd; char *port, *base, clienth[NI_MAXHOST], clientp[NI_MAXSERV], *user = NULL, *group = NULL, **bindips = NULL, - *ohost = NULL, *sport = NULL, *p; + *ohost = NULL, *sport = NULL, *p, *certfile = NULL, + *keyfile = NULL, shufbuf[1025], byte0, recvb[1025]; struct passwd *us = NULL; struct group *gr = NULL; + struct tls_config *tlsconfig = NULL; + struct tls *tlsctx = NULL, *tlsclientctx; base = stdbase; port = stdport; @@ -483,6 +478,11 @@ main(int argc, char *argv[]) case 'n': revlookup = 0; break; + case 't': + dotls = 1; + keyfile = EARGF(usage()); + certfile = EARGF(usage()); + break; default: usage(); } ARGEND; @@ -493,6 +493,33 @@ main(int argc, char *argv[]) if (argc != 0) usage(); + if (dotls) { + if (tls_init() < 0) { + perror("tls_init"); + return 1; + } + if ((tlsconfig = tls_config_new()) == NULL) { + perror("tls_config_new"); + return 1; + } + if ((tlsctx = tls_server()) == NULL) { + perror("tls_server"); + return 1; + } + if (tls_config_set_key_file(tlsconfig, keyfile) < 0) { + perror("tls_config_set_key_file"); + return 1; + } + if (tls_config_set_cert_file(tlsconfig, certfile) < 0) { + perror("tls_config_set_cert_file"); + return 1; + } + if (tls_configure(tlsctx, tlsconfig) < 0) { + perror("tls_configure"); + return 1; + } + } + if (ohost == NULL) { /* Do not use HOST_NAME_MAX, it is not defined on NetBSD. */ ohost = xcalloc(1, 256+1); @@ -716,16 +743,97 @@ main(int argc, char *argv[]) } #endif /* __OpenBSD__ */ - handlerequest(sock, base, ohost, sport, clienth, - clientp, nocgi); + if (recv(sock, &byte0, 1, MSG_PEEK) < 1) + return 1; + + /* + * First byte is 0x16 == 22, which is the TLS + * Handshake first byte. + */ + istls = 0; + if (byte0 == 0x16 && dotls) { + istls = 1; + if (tls_accept_socket(tlsctx, &tlsclientctx, sock) < 0) + return 1; + if (tls_handshake(tlsclientctx) < 0) + return 1; + } - waitforpendingbytes(sock); + maxrecv = sizeof(recvb) - 1; + do { + if (istls) { + retl = tls_read(tlsclientctx, + recvb+rlen, sizeof(recvb)-1-rlen); + } else { + retl = read(sock, recvb+rlen, + sizeof(recvb)-1-rlen); + } + if (retl <= 0) { + if (retl < 0) + perror("recv"); + break; + } + rlen += retl; + } while (recvb[rlen-1] != '\n' + && --maxrecv > 0); + if (rlen <= 0) + return 1; - shutdown(sock, SHUT_RDWR); + if (istls) { + if (pipe(tlspipe) < 0) { + perror("tls_pipe"); + return 1; + } + + switch(fork()) { + case 0: + sock = tlspipe[1]; + close(tlspipe[0]); + break; + case -1: + perror("fork"); + return 1; + default: + close(tlspipe[1]); + do { + shuflen = read(tlspipe[0], shufbuf, sizeof(shufbuf)-1); + if (shuflen == EINTR) + continue; + for (shufpos = 0; shufpos < shuflen; shufpos += wlen) { + wlen = tls_write(tlsclientctx, shufbuf+shufpos, shuflen-shufpos); + if (wlen < 0) { + printf("tls_write failed: %s\n", tls_error(tlsclientctx)); + return 1; + } + } + } while(shuflen > 0); + + tls_close(tlsclientctx); + tls_free(tlsclientctx); + close(tlspipe[0]); + + waitforpendingbytes(sock); + shutdown(sock, SHUT_RDWR); + close(sock); + return 0; + } + } + + handlerequest(sock, recvb, rlen, base, + ohost, sport, clienth, + clientp, nocgi); + + if (!istls) { + waitforpendingbytes(sock); + shutdown(sock, SHUT_RDWR); + close(sock); + } close(sock); - if (loglvl & CONN) - logentry(clienth, clientp, "-", "disconnected"); + if (loglvl & CONN) { + logentry(clienth, clientp, "-", + "disconnected"); + } return 0; default: @@ -746,6 +854,12 @@ main(int argc, char *argv[]) } free(listfds); + if (dotls) { + tls_close(tlsctx); + tls_free(tlsctx); + tls_config_free(tlsconfig); + } + return 0; }