sacc

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

commit 9dec9b200c1bddd6d12f4aa6b43e2c329f513235
parent 392dcb24732c88f500266b923bafdda8eb631220
Author: Quentin Rameau <quinq@fifth.space>
Date:   Sat, 15 Oct 2022 12:50:09 +0200

tls: Handle local certificate path

Although I believe that every computer should have a user "quinq",
use "~/share/sacc/cert" path by default for looking up certificates.

Also, let the user override this default with the environment variable
SACC_CERT_DIR.

Diffstat:
Mio.h | 1+
Mio_clr.c | 7+++++++
Mio_tls.c | 154+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Msacc.c | 1+
4 files changed, 132 insertions(+), 31 deletions(-)

diff --git a/io.h b/io.h @@ -14,6 +14,7 @@ struct cnx { extern int tls; +extern int (*iosetup)(void); extern int (*ioclose)(struct cnx *); extern int (*ioconnect)(struct cnx *, struct addrinfo *, const char *); extern void (*ioconnerr)(struct cnx *, const char *, const char *, int); diff --git a/io_clr.c b/io_clr.c @@ -8,6 +8,12 @@ #include "io.h" static int +setup_clr(void) +{ + return 0; +} + +static int close_clr(struct cnx *c) { return close(c->sock); @@ -55,6 +61,7 @@ write_clr(struct cnx *c, void *buf, size_t bs) return write(c->sock, buf, bs); } +int (*iosetup)(void) = setup_clr; 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; diff --git a/io_tls.c b/io_tls.c @@ -1,4 +1,6 @@ +#include <errno.h> #include <limits.h> +#include <pwd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -6,6 +8,7 @@ #include <netdb.h> #include <sys/socket.h> +#include <sys/stat.h> #include <tls.h> @@ -16,8 +19,71 @@ #define TLS_ON 1 #define TLS_PEM 2 +struct pem { + char path[PATH_MAX]; + char *dir; + char *cert; + size_t certln; +}; + int tls; +static struct pem pem = { .dir = "share/sacc/cert" }; + +static int +mkpath(char *path, mode_t mode) +{ + char *s; + int r; + + for (s = path+1; (s = strchr(s, '/')) != NULL; ++s) { + s[0] = '\0'; + errno = 0; + r = mkdir(path, mode); + s[0] = '/'; + if (r == -1 && errno != EEXIST) + return -1; + }; + if (mkdir(path, S_IRWXU) == -1 && errno != EEXIST) + return -1; + return 0; +} + +static int +setup_tls(void) +{ + struct passwd *pw; + char *p; + int n; + + if ((p = getenv("SACC_CERT_DIR")) != NULL) { + n = snprintf(pem.path, sizeof(pem.path), "%s/", p); + if (n < 0 || (unsigned)n >= sizeof(pem.path)) { + diag("PEM path too long: %s/", p); + return -1; + } + } else { + if ((pw = getpwuid(geteuid())) == NULL) + return -1; + n = snprintf(pem.path, sizeof(pem.path), "%s/%s/", + pw->pw_dir, pem.dir); + if (n < 0 || (unsigned)n >= sizeof(pem.path)) { + diag("PEM path too long: %s/%s/", pw->pw_dir, pem.dir); + return -1; + } + } + + if (mkpath(pem.path, S_IRWXU) == -1) { + diag("Can't create cert dir: %s: %s", + pem.path, strerror(errno)); + } else { + pem.cert = pem.path + n; + pem.certln = pem.cert - pem.path; + } + + return 0; +} + static int close_tls(struct cnx *c) { @@ -41,6 +107,8 @@ savepem(struct tls *t, char *path) const char *s; size_t ln; + if (path == NULL) + return -1; if ((s = tls_peer_cert_chain_pem(t, &ln)) == NULL) return -1; if ((f = fopen(path, "w")) == NULL) @@ -52,55 +120,77 @@ savepem(struct tls *t, char *path) return 0; } -static int -connect_tls(struct cnx *c, struct addrinfo *ai, const char *host) +static char * +conftls(struct tls *t, const char *host) { - char pempath[PATH_MAX]; - struct tls *t; struct tls_config *tc; - char *s; - int r; + char *p; + int n; - c->tls = NULL; tc = NULL; - s = NULL; - r = -1; + p = NULL; - if (connect(c->sock, ai->ai_addr, ai->ai_addrlen) == -1) - return -1; + if (pem.cert == NULL) + return NULL; - if (!tls) - return 0; - - if ((t = tls_client()) == NULL) - return -1; + n = snprintf(pem.cert, pem.certln, host); + if (n < 0 || (unsigned)n >= pem.certln) { + diag("PEM path too long: %s/%s", pem.cert, host); + return NULL; + } -/* XXX: construct path from getuid home path */ - snprintf(pempath, sizeof(pempath), "/home/quinq/share/sacc/%s.pem", host); switch (tls) { case TLS_ON: /* check if there is a local certificate for target */ - if (access(pempath, R_OK) == 0) { + if (access(pem.path, R_OK) == 0) { if ((tc = tls_config_new()) == NULL) - goto end; - if (tls_config_set_ca_file(tc, pempath) == -1) + return NULL; + if (tls_config_set_ca_file(tc, pem.path) == -1) goto end; if (tls_configure(t, tc) == -1) goto end; + p = pem.path; } break; case TLS_PEM: /* save target certificate to file */ if ((tc = tls_config_new()) == NULL) - goto end; + return NULL; tls_config_insecure_noverifycert(tc); if (tls_configure(t, tc) == -1) goto end; + p = pem.path; break; } +end: + tls_config_free(tc); + return p; +} + +static int +connect_tls(struct cnx *c, struct addrinfo *ai, const char *host) +{ + struct tls *t; + char *s, *pempath; + int r; + + c->tls = NULL; + s = NULL; + r = CONN_ERROR; + + if (connect(c->sock, ai->ai_addr, ai->ai_addrlen) == -1) + return r; + + if (!tls) + return CONN_VALID; + + if ((t = tls_client()) == NULL) + return r; + + pempath = conftls(t, host); if (tls_connect_socket(t, c->sock, host) == -1) - return -1; + goto end; do { r = tls_handshake(t); @@ -120,13 +210,15 @@ connect_tls(struct cnx *c, struct addrinfo *ai, const char *host) diag("Can't establish TLS with \"%s\": %s", host, tls_error(t)); - s = uiprompt("Save certificate locally and retry? [yN]: "); - switch (*s) { - case 'Y': - case 'y': - tls = TLS_PEM; - r = CONN_RETRY; - goto end; + if (pem.cert) { + s = uiprompt("Save certificate locally and retry? [yN]: "); + switch (*s) { + case 'Y': + case 'y': + tls = TLS_PEM; + r = CONN_RETRY; + goto end; + } } s = uiprompt("Retry on cleartext? [Yn]: "); @@ -143,7 +235,6 @@ connect_tls(struct cnx *c, struct addrinfo *ai, const char *host) } end: free(s); - tls_config_free(tc); if (r != CONN_VALID) tls_free(t); @@ -219,6 +310,7 @@ write_tls(struct cnx *c, void *buf, size_t bs) return n; } +int (*iosetup)(void) = setup_tls; 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; diff --git a/sacc.c b/sacc.c @@ -1113,6 +1113,7 @@ setup(void) } else { diag = stddiag; } + iosetup(); } int