Add tls support to geomyidae. - geomyidae - A small C-based gopherd.
git clone git://bitreich.org/geomyidae/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/geomyidae/
Log
Files
Refs
Tags
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:
  M Makefile                            |       2 +-
  M handlr.c                            |      11 +++++++----
  M 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 
 #include 
 #include 
+#include 
+
 #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 
 #include 
 #include 
+#include 
 
 #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;
 }