tAdd TLS support - sacc - sacc (saccomys): simple gopher client.
Log
Files
Refs
LICENSE
---
commit 92394502830c460c78633f56a69da4ce5f01d5fa
parent a58414c67ddf05ff48b8a86fb2d3cf5e58cea4b9
Author: Quentin Rameau 
Date:   Fri,  9 Apr 2021 23:58:34 +0200

Add TLS support

TLS will be used when a gophers:// URL is requested.

Diffstat:
  M Makefile                            |       4 ++--
  M config.mk                           |       4 ++++
  M sacc.c                              |     124 ++++++++++++++++++++++++++-----

3 files changed, 110 insertions(+), 22 deletions(-)
---
diff --git a/Makefile b/Makefile
t@@ -14,7 +14,7 @@ config.h:
         cp config.def.h config.h
 
 $(BIN): $(OBJ)
-        $(CC) $(OBJ) $(LDFLAGS) $(LIBS) -o $@
+        $(CC) $(OBJ) $(LDFLAGS) $(LIBS) $(TLSLIBS) -o $@
 
 $(OBJ): config.h config.mk common.h
 
t@@ -33,7 +33,7 @@ uninstall:
 
 # Stock FLAGS
 SACCCFLAGS = -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=700 -D_BSD_SOURCE -D_GNU_SOURCE \
-             $(CFLAGS)
+             $(TLSCFLAGS) $(CFLAGS)
 
 .c.o:
         $(CC) $(SACCCFLAGS) -c $<
diff --git a/config.mk b/config.mk
t@@ -12,3 +12,7 @@ LIBS=-lcurses
 # Define NEED_ASPRINTF and/or NEED_STRCASESTR in your cflags if your system does
 # not provide asprintf() or strcasestr(), respectively.
 #CFLAGS = -DNEED_ASPRINTF -DNEED_STRCASESTR
+
+# gophers (gopher over TLS) support
+TLSCFLAGS = -DUSE_TLS
+TLSLIBS = -ltls
diff --git a/sacc.c b/sacc.c
t@@ -18,14 +18,26 @@
 #include 
 #include 
 
+#ifdef USE_TLS
+#include 
+#endif
+
 #include "common.h"
 #include "config.h"
 
+struct cnx {
+#ifdef USE_TLS
+        struct tls *tls;
+#endif
+        int sock;
+};
+
 static char *mainurl;
 static Item *mainentry;
 static int devnullfd;
 static int parent = 1;
 static int interactive;
+static int tls;
 
 static void (*diag)(char *fmt, ...);
 
t@@ -417,7 +429,7 @@ molddiritem(char *raw)
 }
 
 static char *
-getrawitem(int sock)
+getrawitem(struct cnx *cnx)
 {
         char *raw, *buf;
         size_t bn, bs;
t@@ -445,7 +457,18 @@ getrawitem(int sock)
                         buf = raw + (bn-1) * BUFSIZ;
                         bs = BUFSIZ;
                 }
-        } while ((n = read(sock, buf, bs)) > 0);
+
+#ifdef USE_TLS
+                if (tls) {
+                        do {
+                                n = tls_read(cnx->tls, buf, bs);
+                        } while (n == TLS_WANT_POLLIN || n == TLS_WANT_POLLOUT);
+                } else
+#endif
+                {
+                        n = read(cnx->sock, buf, bs);
+                }
+        } while (n > 0);
 
         *buf = '\0';
 
t@@ -458,7 +481,7 @@ getrawitem(int sock)
 }
 
 static int
-sendselector(int sock, const char *selector)
+sendselector(struct cnx *cnx, const char *selector)
 {
         char *msg, *p;
         size_t ln;
t@@ -468,10 +491,21 @@ sendselector(int sock, const char *selector)
         msg = p = xmalloc(ln);
         snprintf(msg, ln--, "%s\r\n", selector);
 
-        while ((n = write(sock, p, ln)) > 0) {
+        do {
+#ifdef USE_TLS
+                if (tls) {
+                        do {
+                                n = tls_write(cnx->tls, p, ln);
+                        } while (n == TLS_WANT_POLLIN || n == TLS_WANT_POLLOUT);
+                } else
+#endif
+                {
+                        n = write(cnx->sock, p, ln);
+                }
+
                 ln -= n;
                 p += n;
-        }
+        } while (n > 0);
 
         free(msg);
         if (n == -1)
t@@ -480,8 +514,20 @@ sendselector(int sock, const char *selector)
         return n;
 }
 
+static void
+closecnx(struct cnx *cnx)
+{
+#ifdef USE_TLS
+        if (tls) {
+                tls_close(cnx->tls);
+                tls_free(cnx->tls);
+        }
+#endif
+        close(cnx->sock);
+}
+
 static int
-connectto(const char *host, const char *port)
+connectto(const char *host, const char *port, struct cnx *cnx)
 {
         sigset_t set, oset;
         static const struct addrinfo hints = {
t@@ -506,10 +552,23 @@ connectto(const char *host, const char *port)
                 if ((sock = socket(addr->ai_family, addr->ai_socktype,
                                    addr->ai_protocol)) < 0)
                         continue;
-                if ((r = connect(sock, addr->ai_addr, addr->ai_addrlen)) < 0) {
+
+                r = connect(sock, addr->ai_addr, addr->ai_addrlen);
+                if (r == -1) {
                         close(sock);
                         continue;
                 }
+#ifdef USE_TLS
+                if (tls) {
+                        if ((cnx->tls = tls_client()) == NULL) {
+                                diag("Can't establish TLS with \"%s\": %s",
+                                     host, tls_error(cnx->tls));
+                                close(sock);
+                                continue;
+                        }
+                        r = tls_connect_socket(cnx->tls, sock, host);
+                }
+#endif
                 break;
         }
 
t@@ -526,8 +585,10 @@ connectto(const char *host, const char *port)
         }
 
         sigprocmask(SIG_SETMASK, &oset, NULL);
-        return sock;
 
+        cnx->sock = sock;
+
+        return 0;
 err:
         sigprocmask(SIG_SETMASK, &oset, NULL);
         return -1;
t@@ -537,13 +598,15 @@ static int
 download(Item *item, int dest)
 {
         char buf[BUFSIZ];
+        struct cnx cnx;
         ssize_t r, w;
         int src;
 
         if (!item->tag) {
-                if ((src = connectto(item->host, item->port)) < 0 ||
-                    sendselector(src, item->selector) < 0)
+                if (connectto(item->host, item->port, &cnx) < 0 ||
+                    sendselector(&cnx, item->selector) < 0)
                         return 0;
+                src = cnx.sock;
         } else if ((src = open(item->tag, O_RDONLY)) < 0) {
                 printf("Can't open source file %s: %s",
                        item->tag, strerror(errno));
t@@ -551,8 +614,20 @@ download(Item *item, int dest)
                 return 0;
         }
 
-        w = 0;
-        while ((r = read(src, buf, BUFSIZ)) > 0) {
+        for (w = 0; w != -1;) {
+#ifdef USE_TLS
+                if (tls) {
+                        do {
+                                r = tls_read(cnx.tls, buf, sizeof(buf));
+                        } while (r == TLS_WANT_POLLIN || r == TLS_WANT_POLLOUT);
+                } else
+#endif
+                {
+                        r = read(src, buf, sizeof(buf));
+                }
+                if (r <= 0)
+                        break;
+
                 while ((w = write(dest, buf, r)) > 0)
                         r -= w;
         }
t@@ -563,7 +638,7 @@ download(Item *item, int dest)
                 errno = 0;
         }
 
-        close(src);
+        closecnx(&cnx);
 
         return (r == 0 && w == 0);
 }
t@@ -618,14 +693,15 @@ cleanup:
 static int
 fetchitem(Item *item)
 {
-        char *raw, *r;
-        int sock;
+        struct cnx cnx;
+        char *raw;
 
-        if ((sock = connectto(item->host, item->port)) < 0 ||
-            sendselector(sock, item->selector) < 0)
+        if (connectto(item->host, item->port, &cnx) < 0 ||
+            sendselector(&cnx, item->selector) < 0)
                 return 0;
-        raw = getrawitem(sock);
-        close(sock);
+
+        raw = getrawitem(&cnx);
+        closecnx(&cnx);
 
         if (raw == NULL || !*raw) {
                 diag("Empty response from server");
t@@ -910,8 +986,16 @@ moldentry(char *url)
         int parsed, ipv6;
 
         if (p = strstr(url, "://")) {
-                if (strncmp(url, "gopher", p - url))
+                if (strncmp(url, "gopher", p - url) == 0) {
+                        if (tls) {
+                                diag("Switching from gophers to gopher");
+                                tls = 0;
+                        }
+                } else if (strncmp(url, "gophers", p - url) == 0) {
+                        tls = 1;
+                } else {
                         die("Protocol not supported: %.*s", p - url, url);
+                }
                 host = p + 3;
         }