kore/src/domain.c

219 lines
4.4 KiB
C
Raw Permalink Normal View History

/*
2022-01-31 22:02:06 +01:00
* Copyright (c) 2013-2022 Joris Vink <joris@coders.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/param.h>
#include <sys/types.h>
#include <fnmatch.h>
#include "kore.h"
#if !defined(KORE_NO_HTTP)
#include "http.h"
#endif
Add acmev2 (RFC8555) support to Kore. A new acme process is created that communicates with the acme servers. This process does not hold any of your private keys (no account keys, no domain keys etc). Whenever the acme process requires a signed payload it will ask the keymgr process to do the signing with the relevant keys. This process is also sandboxed with pledge+unveil on OpenBSD and seccomp syscall filtering on Linux. The implementation only supports the tls-alpn-01 challenge. This means that you do not need to open additional ports on your machine. http-01 and dns-01 are currently not supported (no wildcard support). A new configuration option "acme_provider" is available and can be set to the acme server its directory. By default this will point to the live letsencrypt environment: https://acme-v02.api.letsencrypt.org/directory The acme process can be controlled via the following config options: - acme_root (where the acme process will chroot/chdir into). - acme_runas (the user the acme process will run as). If none are set, the values from 'root' and 'runas' are taken. If you want to turn on acme for domains you do it as follows: domain kore.io { acme yes } You do not need to specify certkey/certfile anymore, if they are present still they will be overwritten by the acme system. The keymgr will store all certificates and keys under its root (keymgr_root), the account key is stored as "/account-key.pem" and all obtained certificates go under "certificates/<domain>/fullchain.pem" while keys go under "certificates/<domain>/key.pem". Kore will automatically renew certificates if they will expire in 7 days or less.
2019-11-06 19:33:53 +01:00
#if defined(KORE_USE_ACME)
#include "acme.h"
#endif
#define KORE_DOMAIN_CACHE 16
static u_int16_t domain_id = 0;
struct kore_domain *primary_dom = NULL;
static struct kore_domain *cached[KORE_DOMAIN_CACHE];
void
kore_domain_init(void)
{
int i;
for (i = 0; i < KORE_DOMAIN_CACHE; i++)
cached[i] = NULL;
}
void
kore_domain_cleanup(void)
{
}
struct kore_domain *
kore_domain_new(const char *domain)
{
struct kore_domain *dom;
dom = kore_calloc(1, sizeof(*dom));
dom->id = domain_id++;
dom->accesslog = -1;
dom->x509_verify_depth = 1;
dom->domain = kore_strdup(domain);
#if !defined(KORE_NO_HTTP)
TAILQ_INIT(&dom->routes);
TAILQ_INIT(&dom->redirects);
#endif
if (dom->id < KORE_DOMAIN_CACHE) {
if (cached[dom->id] != NULL)
fatal("non free domain cache slot");
cached[dom->id] = dom;
}
if (primary_dom == NULL)
primary_dom = dom;
return (dom);
}
int
kore_domain_attach(struct kore_domain *dom, struct kore_server *server)
{
struct kore_domain *d;
if (dom->server != NULL)
return (KORE_RESULT_ERROR);
TAILQ_FOREACH(d, &server->domains, list) {
if (!strcmp(d->domain, dom->domain))
return (KORE_RESULT_ERROR);
}
dom->server = server;
TAILQ_INSERT_TAIL(&server->domains, dom, list);
/* The primary domain should be attached to a TLS context. */
if (server->tls == 0 && dom == primary_dom)
primary_dom = NULL;
return (KORE_RESULT_OK);
}
void
kore_domain_free(struct kore_domain *dom)
{
#if !defined(KORE_NO_HTTP)
struct kore_route *rt;
struct http_redirect *rdr;
#endif
if (dom == NULL)
return;
if (primary_dom == dom)
primary_dom = NULL;
TAILQ_REMOVE(&dom->server->domains, dom, list);
if (dom->domain != NULL)
kore_free(dom->domain);
kore_tls_domain_cleanup(dom);
kore_free(dom->cafile);
kore_free(dom->certkey);
kore_free(dom->certfile);
kore_free(dom->crlfile);
#if !defined(KORE_NO_HTTP)
/* Drop all handlers associated with this domain */
while ((rt = TAILQ_FIRST(&dom->routes)) != NULL) {
TAILQ_REMOVE(&dom->routes, rt, list);
kore_route_free(rt);
}
while ((rdr = TAILQ_FIRST(&(dom->redirects))) != NULL) {
TAILQ_REMOVE(&(dom->redirects), rdr, list);
regfree(&rdr->rctx);
kore_free(rdr->target);
kore_free(rdr);
}
#endif
kore_free(dom);
}
void
kore_domain_callback(void (*cb)(struct kore_domain *))
{
struct kore_server *srv;
struct kore_domain *dom;
LIST_FOREACH(srv, &kore_servers, list) {
TAILQ_FOREACH(dom, &srv->domains, list) {
cb(dom);
}
}
}
struct kore_domain *
kore_domain_lookup(struct kore_server *srv, const char *domain)
{
struct kore_domain *dom;
TAILQ_FOREACH(dom, &srv->domains, list) {
if (!strcmp(dom->domain, domain))
return (dom);
if (!fnmatch(dom->domain, domain, FNM_CASEFOLD))
return (dom);
}
return (NULL);
}
struct kore_domain *
kore_domain_byid(u_int16_t id)
{
struct kore_server *srv;
struct kore_domain *dom;
if (id < KORE_DOMAIN_CACHE)
return (cached[id]);
LIST_FOREACH(srv, &kore_servers, list) {
TAILQ_FOREACH(dom, &srv->domains, list) {
if (dom->id == id)
return (dom);
}
}
return (NULL);
}
/*
* Called by the worker processes to close the file descriptor towards
* the accesslog as they do not need it locally.
*/
void
kore_domain_closelogs(void)
{
struct kore_server *srv;
struct kore_domain *dom;
LIST_FOREACH(srv, &kore_servers, list) {
TAILQ_FOREACH(dom, &srv->domains, list) {
if (dom->accesslog != -1) {
(void)close(dom->accesslog);
/*
* Turn into flag to indicate accesslogs
* are active.
*/
dom->accesslog = 1;
} else {
dom->accesslog = 0;
}
2016-02-25 22:04:24 +01:00
}
}
}