URI: 
       tAdd support for Gopher over TLS. - sacc - sacc(omys), simple console gopher client (mirror)
  HTML git clone https://git.parazyd.org/sacc
   DIR Log
   DIR Files
   DIR Refs
   DIR LICENSE
       ---
   DIR commit c3bb55bb797cb476a5f26b148e1572521e389313
   DIR parent eae2a995544b2b48c3a7debcb186a00aa0c400b3
  HTML Author: parazyd <parazyd@dyne.org>
       Date:   Tue,  6 Apr 2021 13:24:32 +0200
       
       Add support for Gopher over TLS.
       
       This implementation uses libtls and acts on gophers:// URIs.
       
       Diffstat:
         M config.mk                           |       4 ++++
         M sacc.c                              |      72 ++++++++++++++++++++++++++-----
         A tls.h                               |      15 +++++++++++++++
       
       3 files changed, 81 insertions(+), 10 deletions(-)
       ---
   DIR 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
       +
       +# Define USE_TLS if you want Gopher over TLS support as gophers:// URIs
       +#CFLAGS = -DUSE_TLS
       +#LIBS = -lcurses -ltls
   DIR diff --git a/sacc.c b/sacc.c
       t@@ -19,6 +19,7 @@
        #include <sys/wait.h>
        
        #include "common.h"
       +#include "tls.h"
        
        #include "config.h"
        
       t@@ -27,6 +28,8 @@ static Item *mainentry;
        static int devnullfd;
        static int parent = 1;
        static int interactive;
       +static int dotls = 0;
       +static struct tls *tlsctx = NULL;
        
        static void (*diag)(char *fmt, ...);
        
       t@@ -54,6 +57,40 @@ die(const char *fmt, ...)
                exit(1);
        }
        
       +static ssize_t
       +read_wrap(int s, void *buf, size_t bs)
       +{
       +        if (tlsctx) {
       +                ssize_t r = TLS_WANT_POLLIN;
       +                while (r == TLS_WANT_POLLIN || r == TLS_WANT_POLLOUT)
       +                        r = tls_read(tlsctx, buf, bs);
       +                return r;
       +        }
       +        return read(s, buf, bs);
       +}
       +
       +static ssize_t
       +write_wrap(int fd, const void *buf, size_t nbyte)
       +{
       +        if (tlsctx) {
       +                ssize_t r = TLS_WANT_POLLIN;
       +                while (r == TLS_WANT_POLLIN || r == TLS_WANT_POLLOUT)
       +                        r = tls_write(tlsctx, buf, nbyte);
       +                return r;
       +        }
       +        return write(fd, buf, nbyte);
       +}
       +
       +static int
       +close_wrap(int fd)
       +{
       +        if (tlsctx) {
       +                tls_close(tlsctx);
       +                tls_reset(tlsctx);
       +        }
       +        return close(fd);
       +}
       +
        #ifdef NEED_ASPRINTF
        int
        asprintf(char **s, const char *fmt, ...)
       t@@ -435,18 +472,20 @@ getrawitem(int sock)
                                buf = raw + (bn-1) * BUFSIZ;
                                bs = BUFSIZ;
                        }
       -        } while ((n = read(sock, buf, bs)) > 0);
       +        } while ((n = read_wrap(sock, buf, bs)) > 0);
        
                *buf = '\0';
        
                if (n < 0) {
       -                diag("Can't read socket: %s", strerror(errno));
       +                diag("Can't read socket: %s",
       +                     tlsctx ? tls_error(tlsctx) : strerror(errno));
                        clear(&raw);
                }
        
                return raw;
        }
        
       +
        static int
        sendselector(int sock, const char *selector)
        {
       t@@ -458,14 +497,15 @@ sendselector(int sock, const char *selector)
                msg = p = xmalloc(ln);
                snprintf(msg, ln--, "%s\r\n", selector);
        
       -        while ((n = write(sock, p, ln)) > 0) {
       +        while ((n = write_wrap(sock, p, ln)) > 0) {
                        ln -= n;
                        p += n;
                }
        
                free(msg);
                if (n == -1)
       -                diag("Can't send message: %s", strerror(errno));
       +                diag("Can't send message: %s",
       +                     tlsctx ? tls_error(tlsctx) : strerror(errno));
        
                return n;
        }
       t@@ -480,7 +520,7 @@ connectto(const char *host, const char *port)
                    .ai_protocol = IPPROTO_TCP,
                };
                struct addrinfo *addrs, *addr;
       -        int r, sock = -1;
       +        int r, t = 0, sock = -1;
        
                sigemptyset(&set);
                sigaddset(&set, SIGWINCH);
       t@@ -497,9 +537,13 @@ connectto(const char *host, const char *port)
                                           addr->ai_protocol)) < 0)
                                continue;
                        if ((r = connect(sock, addr->ai_addr, addr->ai_addrlen)) < 0) {
       -                        close(sock);
       +                        close_wrap(sock);
                                continue;
                        }
       +                if (dotls) {
       +                        tlsctx = tls_client();
       +                        t = tls_connect_socket(tlsctx, sock, host);
       +                }
                        break;
                }
        
       t@@ -514,6 +558,10 @@ connectto(const char *host, const char *port)
                             host, port, strerror(errno));
                        goto err;
                }
       +        if (t < 0) {
       +                diag("Can't init TLS : %s", tls_error(tlsctx));
       +                goto err;
       +        }
        
                sigprocmask(SIG_SETMASK, &oset, NULL);
                return sock;
       t@@ -542,7 +590,7 @@ download(Item *item, int dest)
                }
        
                w = 0;
       -        while ((r = read(src, buf, BUFSIZ)) > 0) {
       +        while ((r = read_wrap(src, buf, BUFSIZ)) > 0) {
                        while ((w = write(dest, buf, r)) > 0)
                                r -= w;
                }
       t@@ -553,7 +601,7 @@ download(Item *item, int dest)
                        errno = 0;
                }
        
       -        close(src);
       +        close_wrap(src);
        
                return (r == 0 && w == 0);
        }
       t@@ -615,7 +663,7 @@ fetchitem(Item *item)
                    sendselector(sock, item->selector) < 0)
                        return 0;
                raw = getrawitem(sock);
       -        close(sock);
       +        close_wrap(sock);
        
                if (raw == NULL || !*raw) {
                        diag("Empty response from server");
       t@@ -900,7 +948,11 @@ moldentry(char *url)
                int parsed, ipv6;
        
                if (p = strstr(url, "://")) {
       -                if (strncmp(url, "gopher", p - url))
       +                if (!strncmp(url, "gopher", p - url))
       +                        dotls = 0;
       +                else if (!strncmp(url, "gophers", p - url))
       +                        dotls = 1;
       +                else
                                die("Protocol not supported: %.*s", p - url, url);
                        host = p + 3;
                }
   DIR diff --git a/tls.h b/tls.h
       t@@ -0,0 +1,15 @@
       +/* See LICENSE file for copyright and license details. */
       +#ifndef USE_TLS
       +
       +#define TLS_WANT_POLLIN  0
       +#define TLS_WANT_POLLOUT 0
       +#define tls_read(a,b,c)  0
       +#define tls_write(a,b,c) 0
       +#define tls_close(a)     0
       +#define tls_reset(a)     0
       +#define tls_error(a)     0
       +#define tls_client()     0
       +#define tls_connect_socket(a,b,c) 0
       +#else
       +#include <tls.h>
       +#endif