diff options
Diffstat (limited to 'irc.c')
-rw-r--r-- | irc.c | 121 |
1 files changed, 70 insertions, 51 deletions
diff --git a/irc.c b/irc.c index 59b467c..1fc2c3f 100644 --- a/irc.c +++ b/irc.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 C. McEnroe <june@causal.agency> +/* Copyright (C) 2020 June McEnroe <june@causal.agency> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,6 +27,9 @@ #include <assert.h> #include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> #include <netdb.h> #include <netinet/in.h> #include <stdarg.h> @@ -41,63 +44,59 @@ #include "chat.h" -struct tls *client; +static struct tls *client; +static struct tls_config *config; -static byte *readFile(size_t *len, FILE *file) { - struct stat stat; - int error = fstat(fileno(file), &stat); - if (error) err(EX_IOERR, "fstat"); +void ircConfig( + bool insecure, const char *trust, const char *cert, const char *priv +) { + int error = 0; + char buf[PATH_MAX]; - byte *buf = malloc(stat.st_size); - if (!buf) err(EX_OSERR, "malloc"); - - rewind(file); - *len = fread(buf, 1, stat.st_size, file); - if (ferror(file)) err(EX_IOERR, "fread"); - - return buf; -} - -void ircConfig(bool insecure, FILE *cert, FILE *priv) { - struct tls_config *config = tls_config_new(); + config = tls_config_new(); if (!config) errx(EX_SOFTWARE, "tls_config_new"); - int error = tls_config_set_ciphers(config, "compat"); - if (error) { - errx( - EX_SOFTWARE, "tls_config_set_ciphers: %s", - tls_config_error(config) - ); - } - if (insecure) { tls_config_insecure_noverifycert(config); tls_config_insecure_noverifyname(config); } + if (trust) { + tls_config_insecure_noverifyname(config); + for (int i = 0; configPath(buf, sizeof(buf), trust, i); ++i) { + error = tls_config_set_ca_file(config, buf); + if (!error) break; + } + if (error) errx(EX_NOINPUT, "%s: %s", trust, tls_config_error(config)); + } + + // Explicitly load the default CA cert file on OpenBSD now so it doesn't + // need to be unveiled. Other systems might use a CA directory, so avoid + // changing the default behavior. +#ifdef __OpenBSD__ + if (!insecure && !trust) { + const char *ca = tls_default_ca_cert_file(); + error = tls_config_set_ca_file(config, ca); + if (error) errx(EX_OSFILE, "%s: %s", ca, tls_config_error(config)); + } +#endif if (cert) { - size_t len; - byte *buf = readFile(&len, cert); - error = tls_config_set_cert_mem(config, buf, len); - if (error) { - errx( - EX_CONFIG, "tls_config_set_cert_mem: %s", - tls_config_error(config) - ); - } - if (priv) { - free(buf); - buf = readFile(&len, priv); + for (int i = 0; configPath(buf, sizeof(buf), cert, i); ++i) { + if (priv) { + error = tls_config_set_cert_file(config, buf); + } else { + error = tls_config_set_keypair_file(config, buf, buf); + } + if (!error) break; } - error = tls_config_set_key_mem(config, buf, len); - if (error) { - errx( - EX_CONFIG, "tls_config_set_key_mem: %s", - tls_config_error(config) - ); + if (error) errx(EX_NOINPUT, "%s: %s", cert, tls_config_error(config)); + } + if (priv) { + for (int i = 0; configPath(buf, sizeof(buf), priv, i); ++i) { + error = tls_config_set_key_file(config, buf); + if (!error) break; } - explicit_bzero(buf, len); - free(buf); + if (error) errx(EX_NOINPUT, "%s: %s", priv, tls_config_error(config)); } client = tls_client(); @@ -105,7 +104,6 @@ void ircConfig(bool insecure, FILE *cert, FILE *priv) { error = tls_configure(client, config); if (error) errx(EX_SOFTWARE, "tls_configure: %s", tls_error(client)); - tls_config_free(config); } int ircConnect(const char *bindHost, const char *host, const char *port) { @@ -152,6 +150,7 @@ int ircConnect(const char *bindHost, const char *host, const char *port) { error = connect(sock, ai->ai_addr, ai->ai_addrlen); if (!error) break; + if (error && errno == EINTR) break; // connect continues asynchronously close(sock); sock = -1; @@ -159,13 +158,29 @@ int ircConnect(const char *bindHost, const char *host, const char *port) { if (sock < 0) err(EX_UNAVAILABLE, "%s:%s", host, port); freeaddrinfo(head); + fcntl(sock, F_SETFD, FD_CLOEXEC); error = tls_connect_socket(client, sock, host); if (error) errx(EX_PROTOCOL, "tls_connect: %s", tls_error(client)); - error = tls_handshake(client); + return sock; +} + +void ircHandshake(void) { + int error; + do { + error = tls_handshake(client); + } while (error == TLS_WANT_POLLIN || error == TLS_WANT_POLLOUT); if (error) errx(EX_PROTOCOL, "tls_handshake: %s", tls_error(client)); - return sock; + tls_config_clear_keys(config); +} + +void ircPrintCert(void) { + size_t len; + ircHandshake(); + const byte *pem = tls_peer_cert_chain_pem(client, &len); + printf("subject= %s\n", tls_peer_cert_subject(client)); + fwrite(pem, len, 1, stdout); } enum { MessageCap = 8191 + 512 }; @@ -235,8 +250,12 @@ static struct Message parse(char *line) { char *key = strsep(&tag, "="); for (uint i = 0; i < TagCap; ++i) { if (strcmp(key, TagNames[i])) continue; - unescape(tag); - msg.tags[i] = tag; + if (tag) { + unescape(tag); + msg.tags[i] = tag; + } else { + msg.tags[i] = ""; + } break; } } |