sacc

sacc (saccomys): simple gopher client.
Log | Files | Refs | LICENSE

commit 5a5611b3293eaac0b26832a54b845c6822736b65
parent e3535c1405eac56a658886023b057944b4b91bc0
Author: Quentin Rameau <quinq@fifth.space>
Date:   Sat, 10 Apr 2021 15:56:05 +0200

TLS: use wrapper functions

Diffstat:
MMakefile | 8++++----
Mconfig.mk | 12++++++++----
Aio.h | 17+++++++++++++++++
Aio_clr.c | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aio_tls.c | 129+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msacc.c | 173++++++++++++++++++++-----------------------------------------------------------
6 files changed, 264 insertions(+), 138 deletions(-)

diff --git a/Makefile b/Makefile @@ -6,7 +6,7 @@ include config.mk BIN = sacc MAN = $(BIN).1 -OBJ = $(BIN:=.o) ui_$(UI).o +OBJ = $(BIN:=.o) ui_$(UI).o io_$(IO).o all: $(BIN) @@ -14,9 +14,9 @@ config.h: cp config.def.h config.h $(BIN): $(OBJ) - $(CC) $(OBJ) $(LDFLAGS) $(LIBS) $(TLSLIBS) -o $@ + $(CC) $(OBJ) $(LDFLAGS) $(IOLIBS) $(LIBS) -o $@ -$(OBJ): config.h config.mk common.h +$(OBJ): config.h config.mk common.h io.h clean: rm -f $(BIN) $(OBJ) @@ -33,7 +33,7 @@ uninstall: # Stock FLAGS SACCCFLAGS = -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=700 -D_BSD_SOURCE -D_GNU_SOURCE \ - $(TLSCFLAGS) $(CFLAGS) + $(IOCFLAGS) $(CFLAGS) .c.o: $(CC) $(SACCCFLAGS) -c $< diff --git a/config.mk b/config.mk @@ -9,10 +9,14 @@ MANDIR = $(PREFIX)/share/man/man1 UI=ti LIBS=-lcurses +# IO type +# clr (clear) +#IO = clr +# tls (Transport Layer Security) +IO = tls +IOLIBS = -ltls +IOCFLAGS = -DUSE_TLS + # 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/io.h b/io.h @@ -0,0 +1,17 @@ +#include <netdb.h> + +struct cnx { +#ifdef USE_TLS + struct tls *tls; +#endif + int sock; +}; + +extern int tls; + +extern int (*ioclose)(struct cnx *); +extern int (*ioconnect)(struct cnx *, struct addrinfo *, const char *); +extern void (*ioconnerr)(struct cnx *, const char *, const char *, int); +extern char *(*ioparseurl)(char *); +extern ssize_t (*ioread)(struct cnx *, void *, size_t); +extern ssize_t (*iowrite)(struct cnx *, void *, size_t); diff --git a/io_clr.c b/io_clr.c @@ -0,0 +1,63 @@ +#include <string.h> +#include <unistd.h> +#include <netdb.h> + +#include <sys/socket.h> + +#include "common.h" +#include "io.h" + +static int +close_clr(struct cnx *c) +{ + return close(c->sock); +} + +static int +connect_clr(struct cnx *c, struct addrinfo *ai, const char *host) +{ + return connect(c->sock, ai->ai_addr, ai->ai_addrlen); +} + +static void +connerr_clr(struct cnx *c, const char *host, const char *port, int err) +{ + if (c->sock == -1) + diag("Can't open socket: %s", strerror(err)); + else + diag("Can't connect to: %s:%s: %s", host, port, strerror(err)); +} + +static char * +parseurl_clr(char *url) +{ + char *p; + + if (p = strstr(url, "://")) { + if (strncmp(url, "gopher", p - url)) + die("Protocol not supported: %.*s", p - url, url); + + url = p + 3; + } + + return url; +} + +static ssize_t +read_clr(struct cnx *c, void *buf, size_t bs) +{ + return read(c->sock, buf, bs); +} + +static ssize_t +write_clr(struct cnx *c, void *buf, size_t bs) +{ + return write(c->sock, buf, bs); +} + +int (*ioclose)(struct cnx *) = close_clr; +int (*ioconnect)(struct cnx *, struct addrinfo *, const char *) = connect_clr; +void (*ioconnerr)(struct cnx *, const char *, const char *, int) = connerr_clr; +char *(*ioparseurl)(char *) = parseurl_clr; +ssize_t (*ioread)(struct cnx *, void *, size_t) = read_clr; +ssize_t (*iowrite)(struct cnx *, void *, size_t) = write_clr; diff --git a/io_tls.c b/io_tls.c @@ -0,0 +1,129 @@ +#include <string.h> +#include <unistd.h> +#include <netdb.h> + +#include <sys/socket.h> + +#include <tls.h> + +#include "common.h" +#include "io.h" + +int tls; + +static int +close_tls(struct cnx *c) +{ + int r; + + if (tls) { + if (c->tls) { + do { + r = tls_close(c->tls); + } while (r == TLS_WANT_POLLIN || r == TLS_WANT_POLLOUT); + } + tls_free(c->tls); + } + + return close(c->sock); +} + +static int +connect_tls(struct cnx *c, struct addrinfo *ai, const char *host) +{ + struct tls *t; + int s; + + c->tls = NULL; + s = c->sock; + + if (connect(s, ai->ai_addr, ai->ai_addrlen) == -1) + return -1; + + if (tls) { + if ((t = tls_client()) == NULL) + return -1; + if (tls_connect_socket(t, s, host) == -1) + return -1; + + c->tls = t; + } + + return 0; +} + +static void +connerr_tls(struct cnx *c, const char *host, const char *port, int err) +{ + if (c->sock == -1) { + diag("Can't open socket: %s", strerror(err)); + } else { + if (tls && c->tls) { + diag("Can't establish TLS with \"%s\": %s", + host, tls_error(c->tls)); + } else { + diag("Can't connect to: %s:%s: %s", host, port, + strerror(err)); + } + } +} + +static char * +parseurl_tls(char *url) +{ + char *p; + + if (p = strstr(url, "://")) { + if (!strncmp(url, "gopher", p - url)) { + if (tls) + diag("Switching from gophers to gopher"); + tls = 0; + } else if (!strncmp(url, "gophers", p - url)) { + tls = 1; + } else { + die("Protocol not supported: %.*s", p - url, url); + } + url = p + 3; + } + + return url; +} + +static ssize_t +read_tls(struct cnx *c, void *buf, size_t bs) +{ + ssize_t n; + + if (tls && c->tls) { + do { + n = tls_read(c->tls, buf, bs); + } while (n == TLS_WANT_POLLIN || n == TLS_WANT_POLLOUT); + } else { + n = read(c->sock, buf, bs); + } + + return n; +} + +static ssize_t +write_tls(struct cnx *c, void *buf, size_t bs) +{ + ssize_t n; + + if (tls) { + do { + n = tls_write(c->tls, buf, bs); + } while (n == TLS_WANT_POLLIN || n == TLS_WANT_POLLOUT); + } else { + n = write(c->sock, buf, bs); + } + + return n; +} + +int (*ioclose)(struct cnx *) = close_tls; +int (*ioconnect)(struct cnx *, struct addrinfo *, const char *) = connect_tls; +void (*ioconnerr)(struct cnx *, const char *, const char *, int) = connerr_tls; +char *(*ioparseurl)(char *) = parseurl_tls; +ssize_t (*ioread)(struct cnx *, void *, size_t) = read_tls; +ssize_t (*iowrite)(struct cnx *, void *, size_t) = write_tls; diff --git a/sacc.c b/sacc.c @@ -18,26 +18,15 @@ #include <sys/types.h> #include <sys/wait.h> -#ifdef USE_TLS -#include <tls.h> -#endif - #include "common.h" +#include "io.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, ...); @@ -429,7 +418,7 @@ molddiritem(char *raw) } static char * -getrawitem(struct cnx *cnx) +getrawitem(struct cnx *c) { char *raw, *buf; size_t bn, bs; @@ -458,17 +447,7 @@ getrawitem(struct cnx *cnx) bs = BUFSIZ; } -#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); + } while ((n = ioread(c, buf, bs)) > 0); *buf = '\0'; @@ -481,7 +460,7 @@ getrawitem(struct cnx *cnx) } static int -sendselector(struct cnx *cnx, const char *selector) +sendselector(struct cnx *c, const char *selector) { char *msg, *p; size_t ln; @@ -491,21 +470,10 @@ sendselector(struct cnx *cnx, const char *selector) msg = p = xmalloc(ln); snprintf(msg, ln--, "%s\r\n", selector); - 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); - } - + while ((n = iowrite(c, p, ln)) > 0) { ln -= n; p += n; - } while (n > 0); + }; free(msg); if (n == -1) @@ -514,20 +482,8 @@ sendselector(struct cnx *cnx, 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, struct cnx *cnx) +connectto(const char *host, const char *port, struct cnx *c) { sigset_t set, oset; static const struct addrinfo hints = { @@ -536,7 +492,7 @@ connectto(const char *host, const char *port, struct cnx *cnx) .ai_protocol = IPPROTO_TCP, }; struct addrinfo *addrs, *addr; - int r, sock = -1; + int r, err; sigemptyset(&set); sigaddset(&set, SIGWINCH); @@ -548,86 +504,54 @@ connectto(const char *host, const char *port, struct cnx *cnx) goto err; } + r = -1; for (addr = addrs; addr; addr = addr->ai_next) { - if ((sock = socket(addr->ai_family, addr->ai_socktype, - addr->ai_protocol)) == -1) - continue; - - r = connect(sock, addr->ai_addr, addr->ai_addrlen); - if (r == -1) { - close(sock); + if ((c->sock = socket(addr->ai_family, addr->ai_socktype, + addr->ai_protocol)) == -1) { + err = errno; 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; - } - freeaddrinfo(addrs); + if ((r = ioconnect(c, addr, host)) == 0) + break; - if (sock == -1) { - diag("Can't open socket: %s", strerror(errno)); - goto err; - } - if (r == -1) { - diag("Can't connect to: %s:%s: %s", - host, port, strerror(errno)); - goto err; + err = errno; + close(c->sock); } - sigprocmask(SIG_SETMASK, &oset, NULL); - - cnx->sock = sock; + freeaddrinfo(addrs); - return 0; + if (r == -1) + ioconnerr(c, host, port, err); err: sigprocmask(SIG_SETMASK, &oset, NULL); - return -1; + + return r; } static int download(Item *item, int dest) { char buf[BUFSIZ]; - struct cnx cnx; + struct cnx c; ssize_t r, w; - int src; - if (!item->tag) { - if (connectto(item->host, item->port, &cnx) == -1 || - sendselector(&cnx, item->selector) == -1) + if (item->tag == NULL) { + if (connectto(item->host, item->port, &c) == -1 || + sendselector(&c, item->selector) == -1) + return 0; + } else { + if ((c.sock = open(item->tag, O_RDONLY)) == -1) { + printf("Can't open source file %s: %s", + item->tag, strerror(errno)); + errno = 0; return 0; - src = cnx.sock; - } else if ((src = open(item->tag, O_RDONLY)) == -1) { - printf("Can't open source file %s: %s", - item->tag, strerror(errno)); - errno = 0; - return 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; + c.tls = NULL; + } + w = 0; + while ((r = ioread(&c, buf, BUFSIZ)) > 0) { while ((w = write(dest, buf, r)) > 0) r -= w; } @@ -638,7 +562,8 @@ download(Item *item, int dest) errno = 0; } - closecnx(&cnx); + close(dest); + ioclose(&c); return (r == 0 && w == 0); } @@ -693,15 +618,15 @@ cleanup: static int fetchitem(Item *item) { - struct cnx cnx; + struct cnx c; char *raw; - if (connectto(item->host, item->port, &cnx) == -1 || - sendselector(&cnx, item->selector) == -1) + if (connectto(item->host, item->port, &c) == -1 || + sendselector(&c, item->selector) == -1) return 0; - raw = getrawitem(&cnx); - closecnx(&cnx); + raw = getrawitem(&c); + ioclose(&c); if (raw == NULL || !*raw) { diag("Empty response from server"); @@ -985,19 +910,7 @@ moldentry(char *url) char *p, *host = url, *port = "70", *gopherpath = "1"; int parsed, ipv6; - if (p = strstr(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; - } + host = ioparseurl(url); if (*host == '[') { ipv6 = 1;