mirror of https://github.com/omar-polo/gmid.git
rework the configless mode: change flags and generate certs
This commit is contained in:
parent
0b00962d37
commit
8443bff77a
|
@ -44,6 +44,7 @@ HAVE_ERR=
|
||||||
HAVE_EXPLICIT_BZERO=
|
HAVE_EXPLICIT_BZERO=
|
||||||
HAVE_GETPROGNAME=
|
HAVE_GETPROGNAME=
|
||||||
HAVE_LIBTLS=
|
HAVE_LIBTLS=
|
||||||
|
HAVE_OPENSSL=
|
||||||
HAVE_RECALLOCARRAY=
|
HAVE_RECALLOCARRAY=
|
||||||
HAVE_STRLCAT=
|
HAVE_STRLCAT=
|
||||||
HAVE_STRLCPY=
|
HAVE_STRLCPY=
|
||||||
|
@ -59,9 +60,15 @@ BINDIR=
|
||||||
INSTALL="install"
|
INSTALL="install"
|
||||||
|
|
||||||
# try to auto detect CFLAGS and LDFLAGS
|
# try to auto detect CFLAGS and LDFLAGS
|
||||||
if which pkg-config 2>/dev/null 1>&2 && pkg-config libtls; then
|
if which pkg-config 2>/dev/null 1>&2; then
|
||||||
CFLAGS=`pkg-config --cflags libtls`
|
if pkg-config libtls; then
|
||||||
LDFLAGS=`pkg-config --libs libtls`
|
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
|
fi
|
||||||
|
|
||||||
# auto detect lex/flex
|
# auto detect lex/flex
|
||||||
|
@ -229,6 +236,7 @@ runtest err ERR || true
|
||||||
runtest explicit_bzero EXPLICIT_BZERO || true
|
runtest explicit_bzero EXPLICIT_BZERO || true
|
||||||
runtest getprogname GETPROGNAME || true
|
runtest getprogname GETPROGNAME || true
|
||||||
runtest libtls LIBTLS || true
|
runtest libtls LIBTLS || true
|
||||||
|
runtest openssl OPENSSL || true
|
||||||
runtest recallocarray RECALLOCARRAY || true
|
runtest recallocarray RECALLOCARRAY || true
|
||||||
runtest strlcat STRLCAT || true
|
runtest strlcat STRLCAT || true
|
||||||
runtest strlcpy STRLCPY || true
|
runtest strlcpy STRLCPY || true
|
||||||
|
@ -241,6 +249,12 @@ if [ ${HAVE_LIBTLS} -eq 0 ]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
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
|
# write config.h
|
||||||
|
|
||||||
|
|
186
gmid.c
186
gmid.c
|
@ -14,6 +14,8 @@
|
||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
@ -23,6 +25,9 @@
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <openssl/pem.h>
|
||||||
|
#include <openssl/x509.h>
|
||||||
|
|
||||||
#include "gmid.h"
|
#include "gmid.h"
|
||||||
|
|
||||||
struct vhost hosts[HOSTSLEN];
|
struct vhost hosts[HOSTSLEN];
|
||||||
|
@ -213,6 +218,119 @@ absolutify_path(const char *path)
|
||||||
return r;
|
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
|
void
|
||||||
yyerror(const char *msg)
|
yyerror(const char *msg)
|
||||||
{
|
{
|
||||||
|
@ -333,7 +451,7 @@ setup_tls(void)
|
||||||
if (tls_config_set_keypair_file(tlsconf, hosts->cert, hosts->key))
|
if (tls_config_set_keypair_file(tlsconf, hosts->cert, hosts->key))
|
||||||
fatal("tls_config_set_keypair_file failed");
|
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)
|
if (tls_config_add_keypair_file(tlsconf, h->cert, h->key) == -1)
|
||||||
fatal("failed to load the keypair (%s, %s)",
|
fatal("failed to load the keypair (%s, %s)",
|
||||||
h->cert, h->key);
|
h->cert, h->key);
|
||||||
|
@ -375,7 +493,7 @@ init_config(void)
|
||||||
for (i = 0; i < HOSTSLEN; ++i)
|
for (i = 0; i < HOSTSLEN; ++i)
|
||||||
hosts[i].dirfd = -1;
|
hosts[i].dirfd = -1;
|
||||||
|
|
||||||
conf.foreground = 1;
|
conf.foreground = 0;
|
||||||
conf.port = 1965;
|
conf.port = 1965;
|
||||||
conf.ipv6 = 0;
|
conf.ipv6 = 0;
|
||||||
conf.protos = TLS_PROTOCOL_TLSv1_2 | TLS_PROTOCOL_TLSv1_3;
|
conf.protos = TLS_PROTOCOL_TLSv1_2 | TLS_PROTOCOL_TLSv1_3;
|
||||||
|
@ -419,8 +537,8 @@ void
|
||||||
usage(const char *me)
|
usage(const char *me)
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"USAGE: %s [-n] [-c config] | [-6fh] [-C cert] [-d root] [-K key] "
|
"USAGE: %s [-n] [-c config] | [-6h] [-d certs-dir] [-H host]"
|
||||||
"[-p port] [-x cgi-bin]\n",
|
" [-p port] [-x cgi] [dir]",
|
||||||
me);
|
me);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,19 +546,16 @@ int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int ch, p[2];
|
int ch, p[2];
|
||||||
const char *config_path = NULL;
|
const char *config_path = NULL, *certs_dir = NULL, *hostname = NULL;
|
||||||
int conftest = 0;
|
int conftest = 0, configless = 0;
|
||||||
|
|
||||||
init_config();
|
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) {
|
switch (ch) {
|
||||||
case '6':
|
case '6':
|
||||||
conf.ipv6 = 1;
|
conf.ipv6 = 1;
|
||||||
break;
|
configless = 1;
|
||||||
|
|
||||||
case 'C':
|
|
||||||
hosts[0].cert = optarg;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'c':
|
case 'c':
|
||||||
|
@ -448,29 +563,26 @@ main(int argc, char **argv)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'd':
|
case 'd':
|
||||||
free((char*)hosts[0].dir);
|
certs_dir = optarg;
|
||||||
if ((hosts[0].dir = absolutify_path(optarg)) == NULL)
|
configless = 1;
|
||||||
fatal("absolutify_path");
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'f':
|
case 'H':
|
||||||
conf.foreground = 1;
|
hostname = optarg;
|
||||||
|
configless = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
usage(*argv);
|
usage(*argv);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case 'K':
|
|
||||||
hosts[0].key = optarg;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'n':
|
case 'n':
|
||||||
conftest = 1;
|
conftest = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'p':
|
case 'p':
|
||||||
conf.port = parse_portno(optarg);
|
conf.port = parse_portno(optarg);
|
||||||
|
configless = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'x':
|
case 'x':
|
||||||
|
@ -478,6 +590,7 @@ main(int argc, char **argv)
|
||||||
if (*optarg == '/')
|
if (*optarg == '/')
|
||||||
optarg++;
|
optarg++;
|
||||||
hosts[0].cgi = optarg;
|
hosts[0].cgi = optarg;
|
||||||
|
configless = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -485,17 +598,36 @@ main(int argc, char **argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
argc -= optind;
|
||||||
|
argv += optind;
|
||||||
|
|
||||||
if (config_path != NULL) {
|
if (config_path != NULL) {
|
||||||
if (hosts[0].cert != NULL || hosts[0].key != NULL ||
|
if (argc > 0 || configless)
|
||||||
hosts[0].dir != NULL)
|
fatal("can't specify options is config mode.");
|
||||||
fatal("can't specify options in conf mode");
|
|
||||||
parse_conf(config_path);
|
parse_conf(config_path);
|
||||||
} else {
|
} else {
|
||||||
if (hosts[0].cert == NULL || hosts[0].key == NULL ||
|
conf.foreground = 1;
|
||||||
hosts[0].dir == NULL)
|
|
||||||
fatal("missing cert, key or root directory to serve");
|
if (hostname == NULL)
|
||||||
hosts[0].domain = "*";
|
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) {
|
if (conftest) {
|
||||||
|
|
4
gmid.h
4
gmid.h
|
@ -168,6 +168,10 @@ int starts_with(const char*, const char*);
|
||||||
int ends_with(const char*, const char*);
|
int ends_with(const char*, const char*);
|
||||||
ssize_t filesize(int);
|
ssize_t filesize(int);
|
||||||
char *absolutify_path(const char*);
|
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*);
|
void yyerror(const char*);
|
||||||
int parse_portno(const char*);
|
int parse_portno(const char*);
|
||||||
void parse_conf(const char*);
|
void parse_conf(const char*);
|
||||||
|
|
3
server.c
3
server.c
|
@ -35,6 +35,9 @@ vhost_lang(struct vhost *v, const char *path)
|
||||||
struct location *loc;
|
struct location *loc;
|
||||||
const char *lang = NULL;
|
const char *lang = NULL;
|
||||||
|
|
||||||
|
if (v == NULL)
|
||||||
|
return lang;
|
||||||
|
|
||||||
for (loc = v->locations; loc->match != NULL; ++loc) {
|
for (loc = v->locations; loc->match != NULL; ++loc) {
|
||||||
if (!fnmatch(loc->match, path, 0)) {
|
if (!fnmatch(loc->match, path, 0)) {
|
||||||
if (loc->lang != NULL)
|
if (loc->lang != NULL)
|
||||||
|
|
Loading…
Reference in New Issue