rework the configless mode: change flags and generate certs

This commit is contained in:
Omar Polo 2021-01-25 14:08:31 +00:00
parent 0b00962d37
commit 8443bff77a
4 changed files with 183 additions and 30 deletions

20
configure vendored
View File

@ -44,6 +44,7 @@ HAVE_ERR=
HAVE_EXPLICIT_BZERO=
HAVE_GETPROGNAME=
HAVE_LIBTLS=
HAVE_OPENSSL=
HAVE_RECALLOCARRAY=
HAVE_STRLCAT=
HAVE_STRLCPY=
@ -59,9 +60,15 @@ BINDIR=
INSTALL="install"
# try to auto detect CFLAGS and LDFLAGS
if which pkg-config 2>/dev/null 1>&2 && pkg-config libtls; then
CFLAGS=`pkg-config --cflags libtls`
LDFLAGS=`pkg-config --libs libtls`
if which pkg-config 2>/dev/null 1>&2; then
if pkg-config libtls; then
CFLAGS="$(pkg-config --cflags libtls)"
LDFLAGS="$(pkg-config --libs libtls)"
fi
if pkg-config openssl; then
CFLAGS="${CFLAGS} $(pkg-config --cflags openssl)"
LDFLAGS="${LDFLAGS} $(pkg-config --libs openssl)"
fi
fi
# auto detect lex/flex
@ -229,6 +236,7 @@ runtest err ERR || true
runtest explicit_bzero EXPLICIT_BZERO || true
runtest getprogname GETPROGNAME || true
runtest libtls LIBTLS || true
runtest openssl OPENSSL || true
runtest recallocarray RECALLOCARRAY || true
runtest strlcat STRLCAT || true
runtest strlcpy STRLCPY || true
@ -241,6 +249,12 @@ if [ ${HAVE_LIBTLS} -eq 0 ]; then
exit 1
fi
if [ ${HAVE_OPENSSL} -eq 0 ]; then
echo "FATAL: openssl not found" 1>&2
echo "FATAL: openssl not found" 1>&3
exit 1
fi
# --------
# write config.h

186
gmid.c
View File

@ -14,6 +14,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
@ -23,6 +25,9 @@
#include <stdarg.h>
#include <string.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
#include "gmid.h"
struct vhost hosts[HOSTSLEN];
@ -213,6 +218,119 @@ absolutify_path(const char *path)
return r;
}
void
gen_certificate(const char *host, const char *certpath, const char *keypath)
{
BIGNUM e;
EVP_PKEY *pkey;
RSA *rsa;
X509 *x509;
X509_NAME *name;
FILE *f;
const char *org = "gmid";
LOGN(NULL, "generating a new certificate for %s in %s (it could take a while)",
host, certpath);
if ((pkey = EVP_PKEY_new()) == NULL)
fatal("couldn't create a new private key");
if ((rsa = RSA_new()) == NULL)
fatal("could'nt generate rsa");
BN_init(&e);
BN_set_word(&e, 17);
if (!RSA_generate_key_ex(rsa, 4096, &e, NULL))
fatal("couldn't generate a rsa key");
if (!EVP_PKEY_assign_RSA(pkey, rsa))
fatal("couldn't assign the key");
if ((x509 = X509_new()) == NULL)
fatal("couldn't generate the X509 certificate");
ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);
X509_gmtime_adj(X509_get_notBefore(x509), 0);
X509_gmtime_adj(X509_get_notAfter(x509), 315360000L); /* 10 years */
if (!X509_set_pubkey(x509, pkey))
fatal("couldn't set the public key");
name = X509_get_subject_name(x509);
if (!X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, org, -1, -1, 0))
fatal("couldn't add N to cert");
if (!X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, host, -1, -1, 0))
fatal("couldn't add CN to cert");
X509_set_issuer_name(x509, name);
if (!X509_sign(x509, pkey, EVP_sha256()))
fatal("couldn't sign the certificate");
if ((f = fopen(keypath, "w")) == NULL)
fatal("fopen(%s): %s", keypath, strerror(errno));
if (!PEM_write_PrivateKey(f, pkey, NULL, NULL, 0, NULL, NULL))
fatal("couldn't write private key");
fclose(f);
if ((f = fopen(certpath, "w")) == NULL)
fatal("fopen(%s): %s", certpath, strerror(errno));
if (!PEM_write_X509(f, x509))
fatal("couldn't write cert");
fclose(f);
X509_free(x509);
RSA_free(rsa);
}
/* XXX: create recursively */
void
mkdirs(const char *path)
{
if (mkdir(path, 0755) == -1 && errno != EEXIST)
fatal("can't mkdir %s: %s", path, strerror(errno));
}
/* $XDG_DATA_HOME/gmid */
char *
data_dir(void)
{
const char *home, *xdg;
char dir[PATH_MAX];
char *t;
if ((xdg = getenv("XDG_DATA_HOME")) == NULL) {
if ((home = getenv("HOME")) == NULL)
errx(1, "XDG_DATA_HOME and HOME both empty");
if (asprintf(&t, "%s/.local/share/gmid", home) == -1)
err(1, "asprintf");
mkdirs(t);
return t;
}
if (asprintf(&t, "%s/gmid", xdg) == -1)
err(1, "asprintf");
mkdirs(t);
return t;
}
void
load_local_cert(const char *hostname, const char *dir)
{
char *cert, *key;
if (asprintf(&cert, "%s/%s.cert.pem", dir, hostname) == -1)
errx(1, "asprintf");
if (asprintf(&key, "%s/%s.key.pem", dir, hostname) == -1)
errx(1, "asprintf");
if (access(cert, R_OK) == -1 || access(key, R_OK) == -1)
gen_certificate(hostname, cert, key);
hosts[0].cert = cert;
hosts[0].key = key;
hosts[0].domain = hostname;
}
void
yyerror(const char *msg)
{
@ -333,7 +451,7 @@ setup_tls(void)
if (tls_config_set_keypair_file(tlsconf, hosts->cert, hosts->key))
fatal("tls_config_set_keypair_file failed");
for (h = hosts; h->domain != NULL; ++h) {
for (h = &hosts[1]; h->domain != NULL; ++h) {
if (tls_config_add_keypair_file(tlsconf, h->cert, h->key) == -1)
fatal("failed to load the keypair (%s, %s)",
h->cert, h->key);
@ -375,7 +493,7 @@ init_config(void)
for (i = 0; i < HOSTSLEN; ++i)
hosts[i].dirfd = -1;
conf.foreground = 1;
conf.foreground = 0;
conf.port = 1965;
conf.ipv6 = 0;
conf.protos = TLS_PROTOCOL_TLSv1_2 | TLS_PROTOCOL_TLSv1_3;
@ -419,8 +537,8 @@ void
usage(const char *me)
{
fprintf(stderr,
"USAGE: %s [-n] [-c config] | [-6fh] [-C cert] [-d root] [-K key] "
"[-p port] [-x cgi-bin]\n",
"USAGE: %s [-n] [-c config] | [-6h] [-d certs-dir] [-H host]"
" [-p port] [-x cgi] [dir]",
me);
}
@ -428,19 +546,16 @@ int
main(int argc, char **argv)
{
int ch, p[2];
const char *config_path = NULL;
int conftest = 0;
const char *config_path = NULL, *certs_dir = NULL, *hostname = NULL;
int conftest = 0, configless = 0;
init_config();
while ((ch = getopt(argc, argv, "6C:c:d:fhK:np:x:")) != -1) {
while ((ch = getopt(argc, argv, "6c:d:H:hnp:x:")) != -1) {
switch (ch) {
case '6':
conf.ipv6 = 1;
break;
case 'C':
hosts[0].cert = optarg;
configless = 1;
break;
case 'c':
@ -448,29 +563,26 @@ main(int argc, char **argv)
break;
case 'd':
free((char*)hosts[0].dir);
if ((hosts[0].dir = absolutify_path(optarg)) == NULL)
fatal("absolutify_path");
certs_dir = optarg;
configless = 1;
break;
case 'f':
conf.foreground = 1;
case 'H':
hostname = optarg;
configless = 1;
break;
case 'h':
usage(*argv);
return 0;
case 'K':
hosts[0].key = optarg;
break;
case 'n':
conftest = 1;
break;
case 'p':
conf.port = parse_portno(optarg);
configless = 1;
break;
case 'x':
@ -478,6 +590,7 @@ main(int argc, char **argv)
if (*optarg == '/')
optarg++;
hosts[0].cgi = optarg;
configless = 1;
break;
default:
@ -485,17 +598,36 @@ main(int argc, char **argv)
return 1;
}
}
argc -= optind;
argv += optind;
if (config_path != NULL) {
if (hosts[0].cert != NULL || hosts[0].key != NULL ||
hosts[0].dir != NULL)
fatal("can't specify options in conf mode");
if (argc > 0 || configless)
fatal("can't specify options is config mode.");
parse_conf(config_path);
} else {
if (hosts[0].cert == NULL || hosts[0].key == NULL ||
hosts[0].dir == NULL)
fatal("missing cert, key or root directory to serve");
hosts[0].domain = "*";
conf.foreground = 1;
if (hostname == NULL)
hostname = "localhost";
if (certs_dir == NULL)
certs_dir = data_dir();
load_local_cert(hostname, certs_dir);
switch (argc) {
case 0:
hosts[0].dir = ".";
break;
case 1:
hosts[0].dir = argv[0];
break;
default:
usage(getprogname());
return 1;
}
LOGN(NULL, "serving %s on port %d", hosts[0].dir, conf.port);
}
if (conftest) {

4
gmid.h
View File

@ -168,6 +168,10 @@ int starts_with(const char*, const char*);
int ends_with(const char*, const char*);
ssize_t filesize(int);
char *absolutify_path(const char*);
void gen_certificate(const char*, const char*, const char*);
void mkdirs(const char*);
char *data_dir(void);
void load_local_cert(const char*, const char*);
void yyerror(const char*);
int parse_portno(const char*);
void parse_conf(const char*);

View File

@ -35,6 +35,9 @@ vhost_lang(struct vhost *v, const char *path)
struct location *loc;
const char *lang = NULL;
if (v == NULL)
return lang;
for (loc = v->locations; loc->match != NULL; ++loc) {
if (!fnmatch(loc->match, path, 0)) {
if (loc->lang != NULL)