commit 92394502830c460c78633f56a69da4ce5f01d5fa
parent a58414c67ddf05ff48b8a86fb2d3cf5e58cea4b9
Author: Quentin Rameau <quinq@fifth.space>
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
@@ -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
@@ -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
@@ -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
@@ -18,14 +18,26 @@
#include <sys/types.h>
#include <sys/wait.h>
+#ifdef USE_TLS
+#include <tls.h>
+#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, ...);
@@ -417,7 +429,7 @@ molddiritem(char *raw)
}
static char *
-getrawitem(int sock)
+getrawitem(struct cnx *cnx)
{
char *raw, *buf;
size_t bn, bs;
@@ -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';
@@ -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;
@@ -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)
@@ -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 = {
@@ -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;
}
@@ -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;
@@ -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));
@@ -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;
}
@@ -563,7 +638,7 @@ download(Item *item, int dest)
errno = 0;
}
- close(src);
+ closecnx(&cnx);
return (r == 0 && w == 0);
}
@@ -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");
@@ -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;
}