Merge branch 'master' into 4.x-releng

This commit is contained in:
Joris Vink 2022-01-24 17:54:37 +01:00
commit e466871b59
89 changed files with 3885 additions and 2653 deletions

6
BEERS
View File

@ -17,20 +17,22 @@ I will note down the beer of your choice between the brackets.
[] Daniel Fahlgren x 2
[] Dmitrii Golub
[] Elliot Schlegelmilch
[] Erik Karlsson
[] Erik Karlsson x 2
[] Frederic Cambus
[] Guy Nankivell
[] James Turner
[] Joel Arbring x 2
[] Manuel Kniep
[] Marcin Szczepaniak
[] Matt Thompson
[] Matthew Norström
[] Nandor Kracser
[] Pascal Borreli
[] Quentin Perez
[] Raphaël Monrouzeau
[] Raymond Pasco
[] Remy Noulin
[] Rickard Lind
[] Rickard Lind x 2
[] Shih-Yuan Lee
[] Stanislav Yudin
[] Stig Telfer

View File

@ -21,9 +21,9 @@ VERSION=$(OBJDIR)/version.c
PYTHON_CURLOPT=misc/curl/python_curlopt.h
S_SRC= src/kore.c src/buf.c src/config.c src/connection.c \
src/domain.c src/filemap.c src/fileref.c src/json.c src/mem.c \
src/msg.c src/module.c src/net.c src/pool.c src/runtime.c src/timer.c \
src/utils.c src/worker.c src/keymgr.c
src/domain.c src/filemap.c src/fileref.c src/json.c src/log.c \
src/mem.c src/msg.c src/module.c src/net.c src/pool.c src/runtime.c \
src/timer.c src/utils.c src/worker.c src/keymgr.c
FEATURES=
FEATURES_INC=
@ -31,7 +31,7 @@ FEATURES_INC=
CFLAGS+=-Wall -Werror -Wstrict-prototypes -Wmissing-prototypes
CFLAGS+=-Wmissing-declarations -Wshadow -Wpointer-arith -Wcast-qual
CFLAGS+=-Wsign-compare -Iinclude/kore -I$(OBJDIR) -std=c99 -pedantic
CFLAGS+=-Wtype-limits
CFLAGS+=-Wtype-limits -fno-common
CFLAGS+=-DPREFIX='"$(PREFIX)"' -fstack-protector-all
ifneq ("$(OPENSSL_PATH)", "")
@ -66,7 +66,7 @@ ifneq ("$(NOHTTP)", "")
FEATURES+=-DKORE_NO_HTTP
else
S_SRC+= src/auth.c src/accesslog.c src/http.c \
src/validator.c src/websocket.c
src/route.c src/validator.c src/websocket.c
endif
ifneq ("$(PGSQL)", "")
@ -132,8 +132,10 @@ ifneq ("$(SANITIZE)", "")
endif
ifeq ("$(OSNAME)", "darwin")
CFLAGS+=-I/opt/local/include/ -I/usr/local/opt/openssl/include
LDFLAGS+=-L/opt/local/lib -L/usr/local/opt/openssl/lib
OSSL_INCL=$(shell pkg-config openssl --cflags)
CFLAGS+=$(OSSL_INCL)
LDFLAGS+=$(shell pkg-config openssl --libs)
FEATURES_INC+=$(OSSL_INCL)
S_SRC+=src/bsd.c
else ifeq ("$(OSNAME)", "linux")
CFLAGS+=-D_GNU_SOURCE=1 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2
@ -160,7 +162,7 @@ $(PLATFORM): $(OBJDIR) force
$(PYTHON_CURLOPT): $(OBJDIR) force
@cp $(PYTHON_CURLOPT) $(OBJDIR)
$(VERSION): force
$(VERSION): $(OBJDIR) force
@if [ -d .git ]; then \
GIT_REVISION=`git rev-parse --short=8 HEAD`; \
GIT_BRANCH=`git rev-parse --abbrev-ref HEAD`; \
@ -174,12 +176,15 @@ $(VERSION): force
echo "No version information found (no .git or RELEASE)"; \
exit 1; \
fi
@printf "const char *kore_build_date = \"%s\";\n" \
`date +"%Y-%m-%d"` >> $(VERSION);
$(KODEV): src/cli.c
$(MAKE) -C kodev
$(KORE): $(OBJDIR) $(S_OBJS)
$(CC) $(S_OBJS) $(LDFLAGS) -o $(KORE)
@echo $(LDFLAGS) > kore.linker
@echo $(FEATURES) $(FEATURES_INC) > kore.features
objects: $(OBJDIR) $(PLATFORM) $(GENERATED) $(S_OBJS)
@ -197,7 +202,9 @@ install:
install -m 644 share/man/kodev.1 $(DESTDIR)$(MAN_DIR)/man1/kodev.1
install -m 555 $(KORE) $(DESTDIR)$(INSTALL_DIR)/$(KORE)
install -m 644 kore.features $(DESTDIR)$(SHARE_DIR)/features
install -m 644 kore.linker $(DESTDIR)$(SHARE_DIR)/linker
install -m 644 include/kore/*.h $(DESTDIR)$(INCLUDE_DIR)
install -m 644 misc/ffdhe4096.pem $(DESTDIR)$(SHARE_DIR)/ffdhe4096.pem
$(MAKE) -C kodev install
$(MAKE) install-sources
@ -253,6 +260,8 @@ tools-install:
$(OBJDIR)/%.o: src/%.c
$(CC) $(CFLAGS) -c $< -o $@
src/kore.c: $(VERSION)
src/python.c: $(PYTHON_CURLOPT)
src/seccomp.c: $(PLATFORM)
@ -260,7 +269,7 @@ src/seccomp.c: $(PLATFORM)
clean:
rm -f $(VERSION)
find . -type f -name \*.o -exec rm {} \;
rm -rf $(KORE) $(OBJDIR) kore.features
rm -rf $(KORE) $(OBJDIR) kore.features kore.linker
$(MAKE) -C kodev clean
releng-build-examples:

View File

@ -35,7 +35,7 @@ License
Documentation
--------------
[Read the documentation](https://docs.kore.io/4.0.0/)
[Read the documentation](https://docs.kore.io/4.1.0/)
Performance
-----------
@ -52,11 +52,11 @@ Kore only supports x64, arm and aarch64 architectures.
Building Kore
-------------
Clone this repository or get the latest release at [https://kore.io/releases/4.0.0](https://kore.io/releases/4.0.0).
Clone this repository or get the latest release at [https://kore.io/releases/4.1.0](https://kore.io/releases/4.1.0).
Requirements
* openssl (1.0.2, 1.1.0 or 1.1.1)
(note: libressl 3.0.0+ works as a replacement)
* openssl 1.1.1 or libressl 3.x
(note: openssl 3.0.0 is currently *not* supported)
Requirement for asynchronous curl (optional)
* libcurl (7.64.0 or higher)

View File

@ -12,7 +12,7 @@
# Server configuration.
server tls {
bind 127.0.0.1 443
#bind_unix /var/run/kore.sock
#unix /var/run/kore.sock
}
#server notls {
@ -20,16 +20,57 @@ server tls {
# tls no
#}
# The worker process root directory. If chrooting was not disabled
# at startup the worker processes will chroot into this directory.
# Kore can have multiple settings for each processes that run under it.
# There are 3 different type of processes:
#
# If this configuration option is not set, Kore will take the current
# working directory as the root.
root /home/joris/src/kore
# 1) Worker processes, these handle the HTTP requests and your code
# runs inside of these.
# 2) The keymgr process, this handles your domain private keys
# and signing during the TLS handshakes. It also holds your
# ACME account-key and will sign ACME requests.
# 3) The acme process, this talks to the ACME servers.
#
# You can individually turn on/off chrooting and dropping user
# privileges per process. The -n and -r command-line options
# are a global override for skipping chroot or dropping user
# permissions on all processes.
#
# If no root/runas options are set in a process, it will inherit the
# default values from the worker processes.
#
# The worker processes will get the current working directory or
# current user if no options where specified for it.
#
# Configures the worker processes.
privsep worker {
# The user the workers will run as.
runas kore
# Worker processes will run as the specified user. If this option is
# missing Kore will run as the current user.
runas joris
# The root directory for the worker processes, if chroot isn't
# skipped, this is the directory it will chroot into.
#
# If not set, Kore will take the current working directory.
root /var/chroot/kore
# We could configure this process to not chroot and only
# chdir into its root directory.
#skip chroot
}
# Configures the keymgr process.
# If TLS is enabled you will need to specify paths to the domain
# certificate and key that Kore will load. This loading is done
# from the keymgr (separate process) and all paths must be relative
# to the keymgr process its root configuration option.
privsep keymgr {
# The user the keymgr will run as.
runas keymgr
# The root directory for the keymgr process. In this example
# we do not turn off chroot for this process so the keymgr
# will chroot into this directory.
root /etc/keymgr
}
# How many worker processes Kore will spawn. If the directive
# worker_set_affinity is set to 1 (the default) Kore will automatically
@ -88,25 +129,6 @@ workers 4
# NOTE: This file location must be inside your chrooted environment.
#rand_file random.data
# Key manager specific options.
# If TLS is enabled you will need to specify paths to the domain
# certificate and key that Kore will load. This loading is done
# from the keymgr (separate process) and all paths must be relative
# to the keymgr_root configuration option.
#
# keymgr_root The root path the keymgr will chdir into.
# If chroot was not disable at startup time
# the keymgr process will chroot into here.
#
# keymgr_runas The user to run the keymgr as.
#
# If privsep and chrooting is enabled at startup time but these
# configuration options were not set, they will take over the
# values from the 'root' and 'runas' configuration options.
#
#keymgr_root
#keymgr_runas
# Filemap settings
# filemap_index Name of the file to be used as the directory
# index for a filemap.
@ -189,18 +211,20 @@ validator v_regex regex ^/test/[a-z]*$
validator v_number regex ^[0-9]*$
validator v_session function v_session_validate
# Specify what TLS version to be used. Default is TLSv1.2
# Specify what TLS version to be used. Default is TLSv1.3 if available.
# Otherwise it will use TLS 1.2.
# Allowed values:
# 1.2 for TLSv1.2 (default)
# 1.0 for TLSv1.0
# both for TLSv1.0 and TLSv1.2
#tls_version 1.2
# 1.3 for TLSv1.3 (default, if available)
# 1.2 for TLSv1.2
# both for TLSv1.2 and TLSv1.3
#tls_version 1.3
# Specify the TLS ciphers that will be used.
#tls_cipher ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK:!kRSA:!kDSA
#tls_cipher AEAD-AES256-GCM-SHA384:AEAD-CHACHA20-POLY1305-SHA256:AEAD-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256
# Required DH parameters for TLS.
#tls_dhparam dh2048.pem
# Required DH parameters for TLS if DHE ciphersuites are in-use.
# Defaults to SHARE_DIR/ffdhe4096.pem, can be overwritten.
#tls_dhparam /usr/local/share/kore/ffdhe4096.pem
# OpenBSD specific settings.
# Add more pledges if your application requires more privileges.
@ -298,24 +322,24 @@ domain localhost {
accesslog /var/log/kore_access.log
# Page handlers with no authentication required.
static /css/style.css serve_style_css
static / serve_index
static /intro.jpg serve_intro
static /b64test serve_b64test
static /upload serve_file_upload
static /lock-test serve_lock_test
static /validator serve_validator
static /params-test serve_params_test
static /private serve_private
route /css/style.css serve_style_css
route / serve_index
route /intro.jpg serve_intro
route /b64test serve_b64test
route /upload serve_file_upload
route /lock-test serve_lock_test
route /validator serve_validator
route /params-test serve_params_test
route /private serve_private
# Restrict some URIs to certain methods
restrict /private post
restrict /validator post get head
# Page handlers with authentication.
static /private/test serve_private_test auth_example
route /private/test serve_private_test auth_example
# Allow access to files from the directory static_files via
# Allow access to files from the directory route_files via
# the /files/ URI.
#
# Note the directory given must be relative to the root configuration
@ -369,7 +393,7 @@ domain localhost {
# client_verify /other/ca.crt
# client_verify_depth 1
# static /css/style.css serve_style_css
# static / serve_index
# dynamic ^/[a-z0-9_]*$ serve_profile
# route /css/style.css serve_style_css
# route / serve_index
# route ^/[a-z0-9_]*$ serve_profile
#}

View File

@ -5,8 +5,6 @@ server tls {
}
workers 1
tls_dhparam dh2048.pem
pledge dns
domain * {
@ -15,6 +13,11 @@ domain * {
certfile cert/server.pem
certkey cert/key.pem
route / http
route /ftp ftp
route / {
handler http
}
route /ftp {
handler ftp
}
}

View File

@ -44,7 +44,7 @@ state_setup(struct http_request *req)
{
struct kore_curl *client;
client = http_state_create(req, sizeof(*client), NULL);
client = http_state_create(req, sizeof(*client));
if (!kore_curl_init(client,
"http://ftp.eu.openbsd.org/pub/OpenBSD/README", KORE_CURL_ASYNC)) {

View File

@ -59,7 +59,7 @@ state_setup(struct http_request *req)
{
struct kore_curl *client;
client = http_state_create(req, sizeof(*client), NULL);
client = http_state_create(req, sizeof(*client));
/* Initialize curl. */
if (!kore_curl_init(client, "https://kore.io", KORE_CURL_ASYNC)) {

View File

@ -6,15 +6,21 @@ server tls {
load ./cookies.so
tls_dhparam dh2048.pem
domain * {
attach tls
certfile cert/server.pem
certkey cert/key.pem
route / serve_cookies
route /secure serve_cookies
route /vault serve_cookies
route / {
handler serve_cookies
}
route /secure {
handler serve_cookies
}
route /vault {
handler serve_cookies
}
}

View File

@ -5,12 +5,14 @@ server tls {
}
load ./cpp.so
tls_dhparam dh2048.pem
domain * {
attach tls
certfile cert/server.pem
certkey cert/key.pem
route / page
route / {
handler page
}
}

View File

@ -1,8 +0,0 @@
-----BEGIN DH PARAMETERS-----
MIIBCAKCAQEAn4f4Qn5SudFjEYPWTbUaOTLUH85YWmmPFW1+b5bRa9ygr+1wfamv
VKVT7jO8c4msSNikUf6eEfoH0H4VTCaj+Habwu+Sj+I416r3mliMD4SjNsUJrBrY
Y0QV3ZUgZz4A8ARk/WwQcRl8+ZXJz34IaLwAcpyNhoV46iHVxW0ty8ND0U4DIku/
PNayKimu4BXWXk4RfwNVP59t8DQKqjshZ4fDnbotskmSZ+e+FHrd+Kvrq/WButvV
Bzy9fYgnUlJ82g/bziCI83R2xAdtH014fR63MpElkqdNeChb94pPbEdFlNUvYIBN
xx2vTUQMqRbB4UdG2zuzzr5j98HDdblQ+wIBAg==
-----END DH PARAMETERS-----

View File

@ -6,8 +6,6 @@ server tls {
load ./generic.so example_load
tls_dhparam dh2048.pem
http_body_max 1024000000
http_body_disk_offload 1024000

View File

@ -2,13 +2,13 @@ Test parameter to integer conversions.
Run:
```
# kodev run
$ kodev run
```
Test:
```
# curl -i -k https://127.0.0.1:8888/?id=123123
# curl -i -k https://127.0.0.1:8888/?id=-123123
$ curl -i -k https://127.0.0.1:8888/?id=123123
$ curl -i -k https://127.0.0.1:8888/?id=-123123
```
The correct integer types should only be represented in the output.

View File

@ -9,8 +9,6 @@ load ./integers.so
workers 2
worker_max_connections 5000
tls_dhparam dh2048.pem
validator v_id regex ^-?[0-9]*.?[0-9]+$
domain * {
@ -18,10 +16,12 @@ domain * {
certfile cert/server.pem
certkey cert/key.pem
route / page
route / {
handler page
methods get
# allowed parameters in the query string for GETs
params qs:get / {
validate id v_id
validate get id v_id
}
}

View File

@ -6,14 +6,14 @@ server tls {
load ./json.so
tls_dhparam dh2048.pem
domain 127.0.0.1 {
attach tls
certfile cert/server.pem
certkey cert/key.pem
route / page
restrict / post
route / {
handler page
methods post
}
}

View File

@ -30,14 +30,24 @@ page(struct http_request *req)
kore_json_init(&json, req->http_body->data, req->http_body->length);
if (!kore_json_parse(&json)) {
kore_buf_appendf(&buf, "%s\n", kore_json_strerror(&json));
kore_buf_appendf(&buf, "%s\n", kore_json_strerror());
} else {
item = kore_json_find_string(json.root, "foo/bar");
if (item != NULL) {
kore_buf_appendf(&buf,
"foo.bar = '%s'\n", item->data.string);
} else {
kore_buf_appendf(&buf, "string foo.bar not found\n");
kore_buf_appendf(&buf, "foo.bar %s\n",
kore_json_strerror());
}
item = kore_json_find_integer_u64(json.root, "foo/integer");
if (item != NULL) {
kore_buf_appendf(&buf,
"foo.integer = '%" PRIu64 "'\n", item->data.u64);
} else {
kore_buf_appendf(&buf, "foo.integer %s\n",
kore_json_strerror());
}
}

View File

@ -1,5 +0,0 @@
*.o
.objs
json_yajl.so
assets.h
cert

View File

@ -1,21 +0,0 @@
This example demonstrates how you can use external libs in your application.
In this case we link against yajl (Yet Another JSON library) in order to
parse a JSON string that was POSTed to the server.
Take a peek at conf/build.conf for different build flavors and how to
link to other libraries.
Run:
```
$ kodev run
```
Test:
```
$ curl -i -k -d '{"foo":{"bar": "Hello world"}}' https://127.0.0.1:8888
```
The result should echo back the foo.bar JSON path value: Hello world.
The yajl repo is available @ https://github.com/lloyd/yajl

View File

@ -1,19 +0,0 @@
# json_yajl build config
# You can switch flavors using: kodev flavor [newflavor]
# The cflags below are shared between flavors
cflags=-Wall -Wmissing-declarations -Wshadow
cflags=-Wstrict-prototypes -Wmissing-prototypes
cflags=-Wpointer-arith -Wcast-qual -Wsign-compare
dev {
# These cflags are added to the shared ones when
# you build the "dev" flavor.
cflags=-g
ldflags=-lyajl
}
#prod {
# You can specify additional CFLAGS here which are only
# included if you build with the "prod" flavor.
#}

View File

@ -1,18 +0,0 @@
# Placeholder configuration
server tls {
bind 127.0.0.1 8888
}
load ./json_yajl.so
tls_dhparam dh2048.pem
domain 127.0.0.1 {
attach tls
certfile cert/server.pem
certkey cert/key.pem
route / page
}

View File

@ -1,98 +0,0 @@
/*
* Copyright (c) 2013-2018 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 <kore/kore.h>
#include <kore/http.h>
#include <yajl/yajl_tree.h>
int page(struct http_request *);
int
page(struct http_request *req)
{
ssize_t ret;
struct kore_buf *buf;
char *body;
yajl_val node, v;
char eb[1024];
u_int8_t data[BUFSIZ];
const char *path[] = { "foo", "bar", NULL };
/* We only allow POST/PUT methods. */
if (req->method != HTTP_METHOD_POST &&
req->method != HTTP_METHOD_PUT) {
http_response_header(req, "allow", "POST, PUT");
http_response(req, HTTP_STATUS_METHOD_NOT_ALLOWED, NULL, 0);
return (KORE_RESULT_OK);
}
/*
* Read the entire received body into a memory buffer.
*/
buf = kore_buf_alloc(128);
for (;;) {
ret = http_body_read(req, data, sizeof(data));
if (ret == -1) {
kore_buf_free(buf);
kore_log(LOG_NOTICE, "error reading body");
http_response(req, 500, NULL, 0);
return (KORE_RESULT_OK);
}
if (ret == 0)
break;
kore_buf_append(buf, data, ret);
}
/* Grab our body data as a NUL-terminated string. */
body = kore_buf_stringify(buf, NULL);
/* Parse the body via yajl now. */
node = yajl_tree_parse(body, eb, sizeof(eb));
if (node == NULL) {
if (strlen(eb)) {
kore_log(LOG_NOTICE, "parse error: %s", eb);
} else {
kore_log(LOG_NOTICE, "parse error: unknown");
}
kore_buf_free(buf);
http_response(req, 400, NULL, 0);
return (KORE_RESULT_OK);
}
/* Reuse old buffer, don't need it anymore for body. */
kore_buf_reset(buf);
/* Attempt to grab foo.bar from the JSON tree. */
v = yajl_tree_get(node, path, yajl_t_string);
if (v == NULL) {
kore_buf_appendf(buf, "no such path: foo.bar\n");
} else {
kore_buf_appendf(buf, "foo.bar = '%s'\n", YAJL_GET_STRING(v));
}
/* Release the JSON tree now. */
yajl_tree_free(node);
/* Respond to the client. */
http_response(req, 200, buf->data, buf->offset);
kore_buf_free(buf);
return (KORE_RESULT_OK);
}

View File

@ -6,14 +6,17 @@ server tls {
load ./jsonrpc.so
tls_dhparam dh2048.pem
domain * {
attach tls
certfile cert/server.pem
certkey cert/key.pem
route / homepage
route /v1 v1
route / {
handler homepage
}
route /v1 {
handler v1
}
}

View File

@ -6,13 +6,13 @@ server tls {
load ./memtag.so init
tls_dhparam dh2048.pem
domain * {
attach tls
certfile cert/server.pem
certkey cert/key.pem
route / page
route / {
handler page
}
}

View File

@ -5,14 +5,18 @@ server tls {
}
load ./messaging.so init
tls_dhparam dh2048.pem
workers 4
domain * {
attach tls
certfile cert/server.pem
certkey cert/key.pem
route / page
route /shutdown page_shutdown
route / {
handler page
}
route /shutdown {
handler page_shutdown
}
}

View File

@ -4,8 +4,6 @@ server tls {
bind 127.0.0.1 8888 connection_setup
}
tls_dhparam dh2048.pem
domain * {
attach tls

View File

@ -6,8 +6,6 @@ server tls {
load ./parameters.so
tls_dhparam dh2048.pem
# The validator used to validate the 'id' parameter
# defined below. We'll use a simple regex to make sure
# it only matches positive numbers.
@ -19,15 +17,10 @@ domain * {
certfile cert/server.pem
certkey cert/key.pem
route / page
route / {
handler page
methods get
# The parameters allowed for "/" (GET method).
#
# If you would want to declare parameters available
# to the page handler for POST, swap the 'get' setting
# to 'post' instead, Kore takes care of the rest.
params qs:get / {
# Validate the id parameter with the v_id validator.
validate id v_id
validate qs:get id v_id
}
}

View File

@ -5,12 +5,14 @@ server tls {
}
load ./pgsql-sync.so init
tls_dhparam dh2048.pem
domain * {
attach tls
certfile cert/server.pem
certkey cert/key.pem
route / page
route / {
handler page
}
}

View File

@ -10,8 +10,6 @@ server other {
bind 127.0.0.1 8889 connection_new
}
tls_dhparam dh2048.pem
http_keepalive_time 0
domain * {
@ -20,6 +18,11 @@ domain * {
certfile cert/server.pem
certkey cert/key.pem
route / page
route /hello hello
route / {
handler page
}
route /hello {
handler hello
}
}

View File

@ -85,7 +85,7 @@ request_perform_init(struct http_request *req)
/* Setup our state context (if not yet set). */
if (!http_state_exists(req)) {
state = http_state_create(req, sizeof(*state), NULL);
state = http_state_create(req, sizeof(*state));
/*
* Initialize the kore_pgsql data structure and bind it

View File

@ -4,8 +4,6 @@ server tls {
bind 127.0.0.1 8888
}
tls_dhparam dh2048.pem
websocket_maxframe 65536
websocket_timeout 10000
@ -15,6 +13,12 @@ domain * {
certfile cert/server.pem
certkey cert/key.pem
route / page
route /connect page_ws_connect
route / {
handler page
}
route /connect {
handler page_ws_connect
methods get
}
}

View File

@ -28,6 +28,7 @@
#include <kore/kore.h>
#include <kore/http.h>
#include <kore/tasks.h>
#include <kore/hooks.h>
#include <fcntl.h>
#include <unistd.h>
@ -49,17 +50,12 @@ void pipe_data_available(struct kore_task *);
/* Our pipe reader. */
struct kore_task pipe_task;
/* Module init function (see config). */
int
init(int state)
void
kore_worker_configure(void)
{
/* Do not allow reload. */
if (state == KORE_MODULE_UNLOAD)
return (KORE_RESULT_ERROR);
/* Only do this on a dedicated worker. */
if (worker->id != 1)
return (KORE_RESULT_OK);
return;
/* Create our task. */
kore_task_create(&pipe_task, pipe_reader);
@ -69,8 +65,6 @@ init(int state)
/* Start the task. */
kore_task_run(&pipe_task);
return (KORE_RESULT_OK);
}
/* Called whenever we get a new websocket connection. */

View File

@ -3,9 +3,11 @@ Kore python async/await examples.
This example also shows off the asynchronous HTTP client support
and requires libcurl on your machine.
Requires that Kore is built with PYTHON=1 CURL=1
Run:
```
$ kodev run
$ kore app.py
```
Test:

View File

@ -16,8 +16,13 @@
import kore
from async_queue import queue_helper
import async_http
import async_queue
import async_socket
import async_process
import async_process
# Kore worker started, start the queue helper coroutine.
def kore_worker_configure():
kore.task_create(queue_helper())
kore.server(ip="127.0.0.1", port="8888", tls=False)
kore.domain("*")
kore.task_create(async_queue.queue_helper())

View File

@ -21,6 +21,7 @@
import kore
# Handler called for /httpclient
@kore.route("/httpclient", methods=["get"])
async def httpclient(req):
# Create an httpclient.
client = kore.httpclient("https://kore.io")

View File

@ -28,6 +28,7 @@ import kore
# The shared lock
lock = kore.lock()
@kore.route("/lock", methods=["get"])
async def async_lock(req):
# A kore.lock should be used with the "async with" syntax.
async with lock:

View File

@ -25,6 +25,7 @@
import kore
import json
@kore.route("/proc", methods=["get"])
async def async_proc(req):
#
# You may specify a timeout when creating the kore.proc object.

View File

@ -36,6 +36,7 @@ async def queue_helper():
# Send it on the received queue.
obj["rq"].push(msg)
@kore.route("/queue", methods=["get"])
async def async_queue(req):
# Create our own queue.
rq = kore.queue()

View File

@ -23,6 +23,7 @@
import kore
import socket
@kore.route("/socket", methods=["get"])
async def async_socket(req):
# Create the socket using Pythons built-in socket class.
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@ -51,6 +52,7 @@ async def async_socket(req):
conn.close()
@kore.route("/socket-test", methods=["get"])
async def socket_test(req):
# Delay response a bit, just cause we can.
await kore.suspend(5000)

View File

@ -1,34 +0,0 @@
# python-async build config
# You can switch flavors using: kodev flavor [newflavor]
# Set to yes if you wish to produce a single binary instead
# of a dynamic library. If you set this to yes you must also
# set kore_source together with kore_flavor.
single_binary=yes
kore_source=../../
kore_flavor=PYTHON=1 CURL=1 NOTLS=1 DEBUG=1
# The flags below are shared between flavors
cflags=-Wall -Wmissing-declarations -Wshadow
cflags=-Wstrict-prototypes -Wmissing-prototypes
cflags=-Wpointer-arith -Wcast-qual -Wsign-compare
cxxflags=-Wall -Wmissing-declarations -Wshadow
cxxflags=-Wpointer-arith -Wcast-qual -Wsign-compare
# Mime types for assets served via the builtin asset_serve_*
#mime_add=txt:text/plain; charset=utf-8
#mime_add=png:image/png
#mime_add=html:text/html; charset=utf-8
dev {
# These flags are added to the shared ones when
# you build the "dev" flavor.
cflags=-g
cxxflags=-g
}
#prod {
# You can specify additional flags here which are only
# included if you build with the "prod" flavor.
#}

View File

@ -1,28 +0,0 @@
# python-async configuration
server notls {
tls no
bind 127.0.0.1 8888
}
python_path src
python_import ./src/setup.py
python_import ./src/async_lock.py
python_import ./src/async_queue.py
python_import ./src/async_process.py
python_import ./src/async_socket.py
python_import ./src/async_http.py
domain * {
attach notls
route /queue async_queue
route /lock async_lock
route /proc async_proc
route /socket async_socket
route /socket-test socket_test
route /httpclient httpclient
}

View File

@ -1,25 +0,0 @@
/*
* Copyright (c) 2020 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 <kore/kore.h>
#include <kore/hooks.h>
/* Let kore handle the default option parsing. */
void
kore_parent_configure(int argc, char **argv)
{
kore_default_getopt(argc, argv);
}

View File

@ -0,0 +1,11 @@
Example of using the asynchronous python api to create a simple
echo server.
Kore must have been built with PYTHON=1.
On the command-line run the following
$ kore echo.py
Then connect to 127.0.0.1 port 6969 using netcat or so and you'll
see it echo back everything you send it.

View File

@ -1,34 +0,0 @@
# python-echo build config
# You can switch flavors using: kodev flavor [newflavor]
# Set to yes if you wish to produce a single binary instead
# of a dynamic library. If you set this to yes you must also
# set kore_source together with kore_flavor.
single_binary=yes
kore_source=../../
kore_flavor=NOTLS=1 PYTHON=1
# The flags below are shared between flavors
cflags=-Wall -Wmissing-declarations -Wshadow
cflags=-Wstrict-prototypes -Wmissing-prototypes
cflags=-Wpointer-arith -Wcast-qual -Wsign-compare
cxxflags=-Wall -Wmissing-declarations -Wshadow
cxxflags=-Wpointer-arith -Wcast-qual -Wsign-compare
# Mime types for assets served via the builtin asset_serve_*
#mime_add=txt:text/plain; charset=utf-8
#mime_add=png:image/png
#mime_add=html:text/html; charset=utf-8
dev {
# These flags are added to the shared ones when
# you build the "dev" flavor.
cflags=-g
cxxflags=-g
}
#prod {
# You can specify additional flags here which are only
# included if you build with the "prod" flavor.
#}

View File

@ -1,3 +0,0 @@
# python-echo configuration
python_import src/echo.py

View File

@ -1,25 +0,0 @@
/*
* Copyright (c) 2020 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 <kore/kore.h>
#include <kore/hooks.h>
/* Let kore handle the default option parsing. */
void
kore_parent_configure(int argc, char **argv)
{
kore_default_getopt(argc, argv);
}

View File

@ -5,8 +5,6 @@ server tls {
}
load ./sse.so
tls_dhparam dh2048.pem
http_keepalive_time 600
domain * {
@ -15,6 +13,11 @@ domain * {
certfile cert/server.pem
certkey cert/key.pem
route / page
route /subscribe subscribe
route / {
handler page
}
route /subscribe {
handler subscribe
}
}

View File

@ -4,8 +4,6 @@ server tls {
bind 127.0.0.1 8888
}
tls_dhparam dh2048.pem
task_threads 4
worker_max_connections 1000
http_keepalive_time 0
@ -19,14 +17,14 @@ domain * {
certkey cert/key.pem
accesslog kore_access.log
route / page_handler
route /post_back post_back
params qs:get / {
validate user v_user
route / {
handler page_handler
validate qs:get user v_user
}
params post /post_back {
validate user v_user
route /post_back {
handler post_back
methods post
validate post user v_user
}
}

View File

@ -1,7 +1,6 @@
# Kore as a TLS proxy configuration.
load ./tls-proxy.so
tls_dhparam dh2048.pem
#
# Bind the proxy to a given IP and port. For every

View File

@ -6,8 +6,6 @@ server tls {
load ./upload.so
tls_dhparam dh2048.pem
http_body_max 1024000000
http_body_disk_offload 4096
@ -17,5 +15,7 @@ domain * {
certfile cert/server.pem
certkey cert/key.pem
route / page
route / {
handler page
}
}

View File

@ -6,8 +6,6 @@ server tls {
load ./video_stream.so init
tls_dhparam dh2048.pem
http_keepalive_time 600
domain * {
@ -17,6 +15,11 @@ domain * {
certkey cert/key.pem
accesslog access.log
route / asset_serve_video_html
route ^/[a-z]*.[a-z0-9]{3}$ video_stream
route / {
handler asset_serve_video_html
}
route ^/[a-z]*.[a-z0-9]{3}$ {
handler video_stream
}
}

View File

@ -6,8 +6,6 @@ server tls {
load ./websocket.so
tls_dhparam dh2048.pem
# Increase workers so connections are spread
# across them to demonstrate WEBSOCKET_BROADCAST_GLOBAL.
workers 4
@ -21,6 +19,11 @@ domain * {
certfile cert/server.pem
certkey cert/key.pem
route / page
route /connect page_ws_connect
route / {
handler page
}
route /connect {
handler page_ws_connect
}
}

View File

@ -54,6 +54,7 @@ int kore_acme_tls_alpn(SSL *, const unsigned char **, unsigned char *,
const unsigned char *, unsigned int, void *);
extern char *acme_email;
extern int acme_domains;
extern char *acme_provider;
#if defined(__cplusplus)

View File

@ -22,6 +22,7 @@
#define KORE_DAEMONIZED_HOOK "kore_parent_daemonized"
void kore_seccomp_hook(void);
void kore_worker_signal(int);
void kore_worker_teardown(void);
void kore_parent_teardown(void);
void kore_worker_configure(void);

View File

@ -119,7 +119,7 @@ struct http_arg {
do { \
int err; \
type nval; \
nval = (type)kore_strtonum64(q->s_value, sign, &err); \
nval = (type)kore_strtonum64(data, sign, &err); \
if (err != KORE_RESULT_OK) \
return (KORE_RESULT_ERROR); \
COPY_ARG_TYPE(nval, type); \
@ -129,7 +129,7 @@ struct http_arg {
do { \
int err; \
type nval; \
nval = kore_strtodouble(q->s_value, min, max, &err); \
nval = kore_strtodouble(data, min, max, &err); \
if (err != KORE_RESULT_OK) \
return (KORE_RESULT_ERROR); \
COPY_ARG_TYPE(nval, type); \
@ -139,7 +139,7 @@ struct http_arg {
do { \
int err; \
int64_t nval; \
nval = kore_strtonum(q->s_value, 10, min, max, &err); \
nval = kore_strtonum(data, 10, min, max, &err); \
if (err != KORE_RESULT_OK) \
return (KORE_RESULT_ERROR); \
COPY_ARG_TYPE(nval, type); \
@ -159,38 +159,62 @@ struct http_arg {
COPY_ARG_INT(min, max, type); \
} while (0)
#define http_argument_type(r, n, so, no, t) \
http_argument_get(r, n, so, no, t)
#define http_argument_get_string(r, n, o) \
http_argument_type(r, n, (void **)o, NULL, HTTP_ARG_TYPE_STRING)
http_argument_get(r, n, (void **)o, NULL, HTTP_ARG_TYPE_STRING)
#define http_argument_get_byte(r, n, o) \
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_BYTE)
http_argument_get(r, n, NULL, o, HTTP_ARG_TYPE_BYTE)
#define http_argument_get_uint16(r, n, o) \
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_UINT16)
http_argument_get(r, n, NULL, o, HTTP_ARG_TYPE_UINT16)
#define http_argument_get_int16(r, n, o) \
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_INT16)
http_argument_get(r, n, NULL, o, HTTP_ARG_TYPE_INT16)
#define http_argument_get_uint32(r, n, o) \
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_UINT32)
http_argument_get(r, n, NULL, o, HTTP_ARG_TYPE_UINT32)
#define http_argument_get_int32(r, n, o) \
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_INT32)
http_argument_get(r, n, NULL, o, HTTP_ARG_TYPE_INT32)
#define http_argument_get_uint64(r, n, o) \
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_UINT64)
http_argument_get(r, n, NULL, o, HTTP_ARG_TYPE_UINT64)
#define http_argument_get_int64(r, n, o) \
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_INT64)
http_argument_get(r, n, NULL, o, HTTP_ARG_TYPE_INT64)
#define http_argument_get_float(r, n, o) \
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_FLOAT)
http_argument_get(r, n, NULL, o, HTTP_ARG_TYPE_FLOAT)
#define http_argument_get_double(r, n, o) \
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_DOUBLE)
http_argument_get(r, n, NULL, o, HTTP_ARG_TYPE_DOUBLE)
#define http_request_header_byte(r, n, o) \
http_request_header_get(r, n, NULL, o, HTTP_ARG_TYPE_BYTE)
#define http_request_header_uint16(r, n, o) \
http_request_header_get(r, n, NULL, o, HTTP_ARG_TYPE_UINT16)
#define http_request_header_int16(r, n, o) \
http_request_header_get(r, n, NULL, o, HTTP_ARG_TYPE_INT16)
#define http_request_header_uint32(r, n, o) \
http_request_header_get(r, n, NULL, o, HTTP_ARG_TYPE_UINT32)
#define http_request_header_int32(r, n, o) \
http_request_header_get(r, n, NULL, o, HTTP_ARG_TYPE_INT32)
#define http_request_header_uint64(r, n, o) \
http_request_header_get(r, n, NULL, o, HTTP_ARG_TYPE_UINT64)
#define http_request_header_int64(r, n, o) \
http_request_header_get(r, n, NULL, o, HTTP_ARG_TYPE_INT64)
#define http_request_header_float(r, n, o) \
http_request_header_get(r, n, NULL, o, HTTP_ARG_TYPE_FLOAT)
#define http_request_header_double(r, n, o) \
http_request_header_get(r, n, NULL, o, HTTP_ARG_TYPE_DOUBLE)
struct http_file {
char *name;
@ -262,13 +286,13 @@ struct http_request {
struct kore_buf *http_body;
int http_body_fd;
char *http_body_path;
size_t http_body_length;
size_t http_body_offset;
size_t content_length;
u_int64_t http_body_length;
u_int64_t http_body_offset;
u_int64_t content_length;
void *hdlr_extra;
size_t state_len;
char *query_string;
struct kore_module_handle *hdlr;
struct kore_route *rt;
struct http_runlock_queue *runlock;
void (*onfree)(struct http_request *);
@ -357,6 +381,10 @@ int http_body_digest(struct http_request *, char *, size_t);
int http_redirect_add(struct kore_domain *,
const char *, int, const char *);
void http_response(struct http_request *, int, const void *, size_t);
void http_response_json(struct http_request *, int,
struct kore_json_item *);
void http_response_close(struct http_request *, int,
const void *, size_t);
void http_response_fileref(struct http_request *, int,
struct kore_fileref *);
void http_serveable(struct http_request *, const void *,
@ -385,8 +413,7 @@ const char *http_media_type(const char *);
void *http_state_get(struct http_request *);
int http_state_exists(struct http_request *);
void http_state_cleanup(struct http_request *);
void *http_state_create(struct http_request *, size_t,
void (*onfree)(struct http_request *));
void *http_state_create(struct http_request *, size_t);
int http_argument_urldecode(char *);
int http_header_recv(struct netbuf *);
@ -396,6 +423,8 @@ void http_populate_multipart_form(struct http_request *);
void http_populate_cookies(struct http_request *);
int http_argument_get(struct http_request *,
const char *, void **, void *, int);
int http_request_header_get(struct http_request *,
const char *, void **, void *, int);
void http_file_rewind(struct http_file *);
ssize_t http_file_read(struct http_file *, void *, size_t);

View File

@ -103,7 +103,8 @@ extern int daemon(int, int);
#define KORE_DOMAINNAME_LEN 255
#define KORE_PIDFILE_DEFAULT "kore.pid"
#define KORE_DEFAULT_CIPHER_LIST "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK:!kRSA:!kDSA"
#define KORE_DHPARAM_PATH PREFIX "/share/kore/ffdhe4096.pem"
#define KORE_DEFAULT_CIPHER_LIST "AEAD-AES256-GCM-SHA384:AEAD-CHACHA20-POLY1305-SHA256:AEAD-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256"
#if defined(KORE_DEBUG)
#define kore_debug(...) \
@ -286,6 +287,9 @@ struct kore_runtime {
int type;
#if !defined(KORE_NO_HTTP)
int (*http_request)(void *, struct http_request *);
void (*http_request_free)(void *, struct http_request *);
void (*http_body_chunk)(void *,
struct http_request *, const void *, size_t);
int (*validator)(void *, struct http_request *, const void *);
void (*wsconnect)(void *, struct connection *);
void (*wsdisconnect)(void *, struct connection *);
@ -294,6 +298,7 @@ struct kore_runtime {
#endif
void (*execute)(void *);
int (*onload)(void *, int);
void (*signal)(void *, int);
void (*connect)(void *, struct connection *);
void (*configure)(void *, int, char **);
};
@ -303,6 +308,37 @@ struct kore_runtime_call {
struct kore_runtime *runtime;
};
#if !defined(KORE_NO_HTTP)
struct kore_route_params {
char *name;
int flags;
u_int8_t method;
struct kore_validator *validator;
TAILQ_ENTRY(kore_route_params) list;
};
struct kore_route {
char *path;
char *func;
int type;
int errors;
int methods;
regex_t rctx;
struct kore_domain *dom;
struct kore_auth *auth;
struct kore_runtime_call *rcall;
struct kore_runtime_call *on_free;
struct kore_runtime_call *on_headers;
struct kore_runtime_call *on_body_chunk;
TAILQ_HEAD(, kore_route_params) params;
TAILQ_ENTRY(kore_route) list;
};
#endif
struct kore_domain {
u_int16_t id;
int logerr;
@ -326,7 +362,7 @@ struct kore_domain {
SSL_CTX *ssl_ctx;
int x509_verify_depth;
#if !defined(KORE_NO_HTTP)
TAILQ_HEAD(, kore_module_handle) handlers;
TAILQ_HEAD(, kore_route) routes;
TAILQ_HEAD(, http_redirect) redirects;
#endif
TAILQ_ENTRY(kore_domain) list;
@ -362,15 +398,6 @@ LIST_HEAD(kore_server_list, kore_server);
#define KORE_PARAMS_QUERY_STRING 0x0001
struct kore_handler_params {
char *name;
int flags;
u_int8_t method;
struct kore_validator *validator;
TAILQ_ENTRY(kore_handler_params) list;
};
#define KORE_AUTH_TYPE_COOKIE 1
#define KORE_AUTH_TYPE_HEADER 2
#define KORE_AUTH_TYPE_REQUEST 3
@ -419,23 +446,6 @@ struct kore_module {
TAILQ_ENTRY(kore_module) list;
};
#if !defined(KORE_NO_HTTP)
struct kore_module_handle {
char *path;
char *func;
int type;
int errors;
regex_t rctx;
struct kore_domain *dom;
struct kore_runtime_call *rcall;
struct kore_auth *auth;
int methods;
TAILQ_HEAD(, kore_handler_params) params;
TAILQ_ENTRY(kore_module_handle) list;
};
#endif
/*
* The workers get a 128KB log buffer per worker, and parent will fetch their
* logs when it reached at least 75% of that or if its been > 1 second since
@ -449,9 +459,17 @@ struct kore_alog_header {
u_int16_t loglen;
} __attribute__((packed));
struct kore_privsep {
char *root;
char *runas;
int skip_runas;
int skip_chroot;
};
struct kore_worker {
u_int16_t id;
u_int16_t cpu;
int ready;
int running;
#if defined(__linux__)
int tracing;
@ -462,7 +480,8 @@ struct kore_worker {
u_int8_t has_lock;
int restarted;
u_int64_t time_locked;
struct kore_module_handle *active_hdlr;
struct kore_route *active_route;
struct kore_privsep *ps;
/* Used by the workers to store accesslogs. */
struct {
@ -570,7 +589,6 @@ struct kore_buf {
struct kore_json {
const u_int8_t *data;
int depth;
int error;
size_t length;
size_t offset;
@ -588,7 +606,7 @@ struct kore_json_item {
char *string;
double number;
int literal;
int64_t s64;
int64_t integer;
u_int64_t u64;
} data;
@ -659,6 +677,7 @@ struct kore_timer {
#define KORE_MSG_CRL 9
#define KORE_MSG_ACCEPT_AVAILABLE 10
#define KORE_PYTHON_SEND_OBJ 11
#define KORE_MSG_WORKER_LOG 12
#define KORE_MSG_ACME_BASE 100
/* messages for applications should start at 201. */
@ -693,6 +712,7 @@ extern char *config_file;
#endif
extern pid_t kore_pid;
extern int kore_quit;
extern int kore_quiet;
extern int kore_debug;
extern int skip_chroot;
@ -700,8 +720,6 @@ extern int skip_runas;
extern int kore_foreground;
extern char *kore_pidfile;
extern char *kore_root_path;
extern char *kore_runas_user;
extern char *kore_tls_cipher_list;
extern volatile sig_atomic_t sig_recv;
@ -710,15 +728,16 @@ extern int tls_version;
extern DH *tls_dhparam;
extern char *rand_file;
extern int keymgr_active;
extern char *keymgr_runas_user;
extern char *keymgr_root_path;
extern char *acme_runas_user;
extern char *acme_root_path;
extern struct kore_privsep worker_privsep;
extern struct kore_privsep keymgr_privsep;
extern struct kore_privsep acme_privsep;
extern u_int8_t nlisteners;
extern u_int16_t cpu_count;
extern u_int8_t worker_count;
extern const char *kore_version;
extern const char *kore_build_date;
extern int worker_policy;
extern u_int8_t worker_set_affinity;
extern u_int32_t worker_rlimit_nofiles;
@ -736,17 +755,19 @@ extern struct kore_server_list kore_servers;
void kore_signal(int);
void kore_shutdown(void);
void kore_signal_trap(int);
void kore_signal_setup(void);
void kore_proctitle(const char *);
void kore_default_getopt(int, char **);
void kore_worker_reap(void);
void kore_worker_init(void);
int kore_worker_init(void);
void kore_worker_privsep(void);
void kore_worker_started(void);
void kore_worker_make_busy(void);
void kore_worker_shutdown(void);
void kore_worker_dispatch_signal(int);
void kore_worker_privdrop(const char *, const char *);
void kore_worker_spawn(u_int16_t, u_int16_t, u_int16_t);
int kore_worker_spawn(u_int16_t, u_int16_t, u_int16_t);
int kore_worker_keymgr_response_verify(struct kore_msg *,
const void *, struct kore_domain **);
@ -845,6 +866,7 @@ int kore_connection_accept(struct listener *,
u_int64_t kore_time_ms(void);
void kore_log_init(void);
void kore_log_file(const char *);
#if defined(KORE_USE_PYTHON)
int kore_configure_setting(const char *, char *);
@ -892,7 +914,11 @@ char *kore_read_line(FILE *, char *, size_t);
EVP_PKEY *kore_rsakey_load(const char *);
EVP_PKEY *kore_rsakey_generate(const char *);
int kore_x509_issuer_name(struct connection *, char **, int);
int kore_x509_subject_name(struct connection *, char **, int);
int kore_x509name_foreach(X509_NAME *, int, void *,
int (*)(void *, int, int, const char *,
const void *, size_t, int));
#if !defined(KORE_NO_HTTP)
void kore_websocket_handshake(struct http_request *,
@ -948,12 +974,16 @@ int kore_domain_attach(struct kore_domain *, struct kore_server *);
void kore_domain_tlsinit(struct kore_domain *, int,
const void *, size_t);
void kore_domain_crl_add(struct kore_domain *, const void *, size_t);
#if !defined(KORE_NO_HTTP)
int kore_module_handler_new(struct kore_domain *, const char *,
const char *, const char *, int);
void kore_module_handler_free(struct kore_module_handle *);
struct kore_module_handle *kore_module_handler_find(struct http_request *,
struct kore_domain *);
void kore_route_reload(void);
void kore_route_free(struct kore_route *);
void kore_route_callback(struct kore_route *, const char *);
struct kore_route *kore_route_create(struct kore_domain *,
const char *, int);
int kore_route_lookup(struct http_request *,
struct kore_domain *, int, struct kore_route **);
#endif
struct kore_runtime_call *kore_runtime_getcall(const char *);
@ -962,11 +992,16 @@ struct kore_module *kore_module_load(const char *,
void kore_runtime_execute(struct kore_runtime_call *);
int kore_runtime_onload(struct kore_runtime_call *, int);
void kore_runtime_signal(struct kore_runtime_call *, int);
void kore_runtime_configure(struct kore_runtime_call *, int, char **);
void kore_runtime_connect(struct kore_runtime_call *, struct connection *);
#if !defined(KORE_NO_HTTP)
int kore_runtime_http_request(struct kore_runtime_call *,
struct http_request *);
void kore_runtime_http_request_free(struct kore_runtime_call *,
struct http_request *);
void kore_runtime_http_body_chunk(struct kore_runtime_call *,
struct http_request *, const void *, size_t);
int kore_runtime_validator(struct kore_runtime_call *,
struct http_request *, const void *);
void kore_runtime_wsconnect(struct kore_runtime_call *, struct connection *);
@ -1038,13 +1073,15 @@ void kore_buf_appendv(struct kore_buf *, const char *, va_list);
void kore_buf_replace_string(struct kore_buf *,
const char *, const void *, size_t);
int kore_json_errno(void);
int kore_json_parse(struct kore_json *);
void kore_json_cleanup(struct kore_json *);
void kore_json_item_free(struct kore_json_item *);
void kore_json_init(struct kore_json *, const void *, size_t);
void kore_json_item_tobuf(struct kore_json_item *, struct kore_buf *);
void kore_json_item_attach(struct kore_json_item *, struct kore_json_item *);
const char *kore_json_strerror(struct kore_json *);
const char *kore_json_strerror(void);
struct kore_json_item *kore_json_find(struct kore_json_item *,
const char *, u_int32_t);
struct kore_json_item *kore_json_create_item(struct kore_json_item *,

View File

@ -21,6 +21,8 @@
#undef _POSIX_C_SOURCE
#undef _XOPEN_SOURCE
#define PY_SSIZE_T_CLEAN 1
#include <Python.h>
#include <frameobject.h>
@ -32,6 +34,7 @@ void kore_python_proc_reap(void);
int kore_python_coro_pending(void);
void kore_python_path(const char *);
void kore_python_coro_delete(void *);
void kore_python_routes_resolve(void);
void kore_python_log_error(const char *);
PyObject *kore_python_callable(PyObject *, const char *);
@ -48,8 +51,11 @@ extern const char *kore_pymodule;
extern struct kore_module_functions kore_python_module;
extern struct kore_runtime kore_python_runtime;
#define KORE_PYTHON_SIGNAL_HOOK "koreapp.signal"
#define KORE_PYTHON_TEARDOWN_HOOK "koreapp.cleanup"
#define KORE_PYTHON_CONFIG_HOOK "koreapp.configure"
#define KORE_PYTHON_DAEMONIZED_HOOK "koreapp.daemonized"
#define KORE_PYTHON_WORKER_STOP_HOOK "koreapp.workerstop"
#define KORE_PYTHON_WORKER_START_HOOK "koreapp.workerstart"
#endif

View File

@ -18,7 +18,7 @@
#define CORO_STATE_SUSPENDED 2
struct python_coro {
u_int32_t id;
u_int64_t id;
int state;
int killed;
PyObject *obj;
@ -45,6 +45,8 @@ static PyObject *python_kore_queue(PyObject *, PyObject *);
static PyObject *python_kore_worker(PyObject *, PyObject *);
static PyObject *python_kore_tracer(PyObject *, PyObject *);
static PyObject *python_kore_fatalx(PyObject *, PyObject *);
static PyObject *python_kore_task_id(PyObject *, PyObject *);
static PyObject *python_kore_sigtrap(PyObject *, PyObject *);
static PyObject *python_kore_setname(PyObject *, PyObject *);
static PyObject *python_kore_suspend(PyObject *, PyObject *);
static PyObject *python_kore_shutdown(PyObject *, PyObject *);
@ -54,6 +56,7 @@ static PyObject *python_kore_task_kill(PyObject *, PyObject *);
static PyObject *python_kore_prerequest(PyObject *, PyObject *);
static PyObject *python_kore_task_create(PyObject *, PyObject *);
static PyObject *python_kore_socket_wrap(PyObject *, PyObject *);
static PyObject *python_kore_route(PyObject *, PyObject *, PyObject *);
static PyObject *python_kore_timer(PyObject *, PyObject *, PyObject *);
static PyObject *python_kore_domain(PyObject *, PyObject *, PyObject *);
static PyObject *python_kore_gather(PyObject *, PyObject *, PyObject *);
@ -61,6 +64,9 @@ static PyObject *python_kore_sendobj(PyObject *, PyObject *,
PyObject *);
static PyObject *python_kore_server(PyObject *, PyObject *,
PyObject *);
static PyObject *python_kore_privsep(PyObject *, PyObject *,
PyObject *);
#if defined(KORE_USE_PGSQL)
static PyObject *python_kore_pgsql_query(PyObject *, PyObject *,
@ -92,6 +98,8 @@ static struct PyMethodDef pykore_methods[] = {
METHOD("tracer", python_kore_tracer, METH_VARARGS),
METHOD("fatal", python_kore_fatal, METH_VARARGS),
METHOD("fatalx", python_kore_fatalx, METH_VARARGS),
METHOD("task_id", python_kore_task_id, METH_NOARGS),
METHOD("sigtrap", python_kore_sigtrap, METH_VARARGS),
METHOD("setname", python_kore_setname, METH_VARARGS),
METHOD("suspend", python_kore_suspend, METH_VARARGS),
METHOD("shutdown", python_kore_shutdown, METH_NOARGS),
@ -101,10 +109,12 @@ static struct PyMethodDef pykore_methods[] = {
METHOD("prerequest", python_kore_prerequest, METH_VARARGS),
METHOD("task_create", python_kore_task_create, METH_VARARGS),
METHOD("socket_wrap", python_kore_socket_wrap, METH_VARARGS),
METHOD("route", python_kore_route, METH_VARARGS | METH_KEYWORDS),
METHOD("timer", python_kore_timer, METH_VARARGS | METH_KEYWORDS),
METHOD("domain", python_kore_domain, METH_VARARGS | METH_KEYWORDS),
METHOD("server", python_kore_server, METH_VARARGS | METH_KEYWORDS),
METHOD("gather", python_kore_gather, METH_VARARGS | METH_KEYWORDS),
METHOD("domain", python_kore_domain, METH_VARARGS | METH_KEYWORDS),
METHOD("privsep", python_kore_privsep, METH_VARARGS | METH_KEYWORDS),
METHOD("sendobj", python_kore_sendobj, METH_VARARGS | METH_KEYWORDS),
METHOD("websocket_broadcast", python_websocket_broadcast, METH_VARARGS),
#if defined(KORE_USE_PGSQL)
@ -186,9 +196,38 @@ static PyTypeObject pyseccomp_type = {
};
#endif
struct pyroute {
PyObject_HEAD
char *path;
PyObject *func;
PyObject *kwargs;
struct kore_domain *domain;
TAILQ_ENTRY(pyroute) list;
};
static PyObject *pyroute_inner(struct pyroute *, PyObject *);
static void pyroute_dealloc(struct pyroute *);
static PyMethodDef pyroute_methods[] = {
METHOD("inner", pyroute_inner, METH_VARARGS),
METHOD(NULL, NULL, -1)
};
static PyTypeObject pyroute_type = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "kore.route",
.tp_doc = "kore route function",
.tp_methods = pyroute_methods,
.tp_basicsize = sizeof(struct pyroute),
.tp_dealloc = (destructor)pyroute_dealloc,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
};
struct pydomain {
PyObject_HEAD
struct kore_domain *config;
struct kore_module_handle *next;
PyObject *kwargs;
};
static PyObject *pydomain_filemaps(struct pydomain *, PyObject *);
@ -659,11 +698,13 @@ static PyObject *pyconnection_get_fd(struct pyconnection *, void *);
static PyObject *pyconnection_get_addr(struct pyconnection *, void *);
static PyObject *pyconnection_get_peer_x509(struct pyconnection *, void *);
static PyObject *pyconnection_get_peer_x509dict(struct pyconnection *, void *);
static PyGetSetDef pyconnection_getset[] = {
GETTER("fd", pyconnection_get_fd),
GETTER("addr", pyconnection_get_addr),
GETTER("x509", pyconnection_get_peer_x509),
GETTER("x509dict", pyconnection_get_peer_x509dict),
GETTER(NULL, NULL),
};
@ -741,8 +782,10 @@ static PyObject *pyhttp_get_path(struct pyhttp_request *, void *);
static PyObject *pyhttp_get_body(struct pyhttp_request *, void *);
static PyObject *pyhttp_get_agent(struct pyhttp_request *, void *);
static PyObject *pyhttp_get_method(struct pyhttp_request *, void *);
static PyObject *pyhttp_get_protocol(struct pyhttp_request *, void *);
static PyObject *pyhttp_get_body_path(struct pyhttp_request *, void *);
static PyObject *pyhttp_get_connection(struct pyhttp_request *, void *);
static PyObject *pyhttp_get_body_digest(struct pyhttp_request *, void *);
static PyGetSetDef pyhttp_request_getset[] = {
GETTER("host", pyhttp_get_host),
@ -750,7 +793,9 @@ static PyGetSetDef pyhttp_request_getset[] = {
GETTER("body", pyhttp_get_body),
GETTER("agent", pyhttp_get_agent),
GETTER("method", pyhttp_get_method),
GETTER("protocol", pyhttp_get_protocol),
GETTER("body_path", pyhttp_get_body_path),
GETTER("body_digest", pyhttp_get_body_digest),
GETTER("connection", pyhttp_get_connection),
GETTER(NULL, NULL)
};
@ -806,12 +851,16 @@ struct pycurl_slist {
LIST_ENTRY(pycurl_slist) list;
};
struct pycurl_data {
struct kore_curl curl;
LIST_HEAD(, pycurl_slist) slists;
};
struct pycurl_handle {
PyObject_HEAD
struct kore_curl curl;
char *url;
struct kore_buf *body;
LIST_HEAD(, pycurl_slist) slists;
struct pycurl_data data;
};
struct pycurl_handle_op {
@ -831,11 +880,11 @@ static PyObject *pycurl_handle_run(struct pycurl_handle *, PyObject *);
static PyObject *pycurl_handle_setopt(struct pycurl_handle *, PyObject *);
static PyObject *pycurl_handle_setbody(struct pycurl_handle *, PyObject *);
static PyObject *pycurl_handle_setopt_string(struct pycurl_handle *,
static PyObject *pycurl_handle_setopt_string(struct pycurl_data *,
int, PyObject *);
static PyObject *pycurl_handle_setopt_long(struct pycurl_handle *,
static PyObject *pycurl_handle_setopt_long(struct pycurl_data *,
int, PyObject *);
static PyObject *pycurl_handle_setopt_slist(struct pycurl_handle *,
static PyObject *pycurl_handle_setopt_slist(struct pycurl_data *,
int, PyObject *);
static PyMethodDef pycurl_handle_methods[] = {
@ -879,6 +928,7 @@ struct pyhttp_client {
char *tlskey;
char *tlscert;
char *cabundle;
PyObject *curlopt;
int tlsverify;
};
@ -886,11 +936,12 @@ struct pyhttp_client_op {
PyObject_HEAD
int state;
int headers;
struct kore_curl curl;
struct python_coro *coro;
struct pyhttp_client *client;
struct pycurl_data data;
};
static PyObject *pyhttp_client_op_await(PyObject *);
static PyObject *pyhttp_client_op_iternext(struct pyhttp_client_op *);

View File

@ -145,7 +145,7 @@
* KORE_SYSCALL_DENY_ERRNO(socket, EACCESS),
* KORE_SYSCALL_DENY_ERRNO(ioctl, EACCESS),
* KORE_SYSCALL_ALLOW(poll),
* );
* )
*/
#define KORE_SECCOMP_FILTER(name, ...) \
struct sock_filter _scfilt[] = { \

View File

@ -28,8 +28,8 @@ endif
OSNAME=$(shell uname -s | sed -e 's/[-_].*//g' | tr A-Z a-z)
ifeq ("$(OSNAME)", "darwin")
CFLAGS+=-I/opt/local/include/ -I/usr/local/opt/openssl/include
LDFLAGS+=-L/opt/local/lib -L/usr/local/opt/openssl/lib
CFLAGS+=$(shell pkg-config openssl --cflags)
LDFLAGS+=$(shell pkg-config openssl --libs)
else ifeq ("$(OSNAME)", "linux")
CFLAGS+=-D_GNU_SOURCE=1
endif

View File

@ -3,7 +3,7 @@
struct {
const char *name;
int value;
PyObject *(*cb)(struct pycurl_handle *, int, PyObject *);
PyObject *(*cb)(struct pycurl_data *, int, PyObject *);
} py_curlopt[] = {
{ "CURLOPT_WRITEDATA", 1, NULL },
{ "CURLOPT_URL", 2, pycurl_handle_setopt_string },

13
misc/ffdhe4096.pem Normal file
View File

@ -0,0 +1,13 @@
-----BEGIN DH PARAMETERS-----
MIICCAKCAgEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
ssbzSibBsu/6iGtCOGEfz9zeNVs7ZRkDW7w09N75nAI4YbRvydbmyQd62R0mkff3
7lmMsPrBhtkcrv4TCYUTknC0EwyTvEN5RPT9RFLi103TZPLiHnH1S/9croKrnJ32
nuhtK8UiNjoNq8Uhl5sN6todv5pC1cRITgq80Gv6U93vPBsg7j/VnXwl5B0rZp4e
8W5vUsMWTfT7eTDp5OWIV7asfV9C1p9tGHdjzx1VA0AEh/VbpX4xzHpxNciG77Qx
iu1qHgEtnmgyqQdgCpGBMMRtx3j5ca0AOAkpmaMzy4t6Gh25PXFAADwqTs6p+Y0K
zAqCkc3OyX3Pjsm1Wn+IpGtNtahR9EGC4caKAH5eZV9q//////////8CAQI=
-----END DH PARAMETERS-----

View File

@ -2,7 +2,12 @@
#
# Linux specific defines and system call maps.
PLATFORM=$(uname -m)
if [ -z "$TARGET_PLATFORM" ]; then
PLATFORM=$(uname -m)
else
PLATFORM=$TARGET_PLATFORM
fi
BASE=$(dirname $0)
case "$PLATFORM" in

View File

@ -18,6 +18,7 @@
#include <sys/socket.h>
#include <time.h>
#include <inttypes.h>
#include <signal.h>
#include "kore.h"
@ -66,7 +67,7 @@ kore_accesslog(struct http_request *req)
size_t avail;
time_t curtime;
int len, attempts;
const char *ptr, *method, *cn, *referer;
const char *ptr, *method, *http_version, *cn, *referer;
char addr[INET6_ADDRSTRLEN], *cn_value;
switch (req->method) {
@ -93,6 +94,12 @@ kore_accesslog(struct http_request *req)
break;
}
if (req->flags & HTTP_VERSION_1_0)
http_version = "HTTP/1.0";
if (req->flags & HTTP_VERSION_1_1)
http_version = "HTTP/1.1";
if (req->referer != NULL)
referer = req->referer;
else
@ -168,9 +175,9 @@ kore_accesslog(struct http_request *req)
worker->lb.offset += sizeof(*hdr);
len = snprintf(worker->lb.buf + worker->lb.offset, avail,
"%s - %s [%s] \"%s %s HTTP/1.1\" %d %zu \"%s\" \"%s\"\n",
addr, cn, tbuf, method, req->path, req->status,
req->content_length, referer, req->agent);
"%s - %s [%s] \"%s %s %s\" %d %" PRIu64" \"%s\" \"%s\"\n",
addr, cn, tbuf, method, req->path, http_version,
req->status, req->content_length, referer, req->agent);
if (len == -1)
fatal("failed to create log entry");
@ -189,7 +196,7 @@ kore_accesslog(struct http_request *req)
}
hdr->loglen = len;
hdr->domain = req->hdlr->dom->id;
hdr->domain = req->rt->dom->id;
worker->lb.offset += (size_t)len;
break;

View File

@ -265,10 +265,10 @@ static char *account_url = NULL;
static u_int8_t acme_alpn_name[] =
{ 0xa, 'a', 'c', 'm', 'e', '-', 't', 'l', 's', '/', '1' };
struct kore_privsep acme_privsep;
int acme_domains = 0;
char *acme_email = NULL;
char *acme_provider = NULL;
char *acme_root_path = NULL;
char *acme_runas_user = NULL;
u_int32_t acme_request_timeout = 8;
void
@ -310,7 +310,7 @@ kore_acme_run(void)
#if defined(KORE_USE_PYTHON)
kore_msg_unregister(KORE_PYTHON_SEND_OBJ);
#endif
kore_worker_privdrop(acme_runas_user, acme_root_path);
kore_worker_privsep();
#if defined(__OpenBSD__)
if (unveil("/etc/ssl/", "r") == -1)
@ -321,14 +321,10 @@ kore_acme_run(void)
http_init();
if (!kore_quiet) {
kore_log(LOG_NOTICE,
"acme worker started (pid#%d)", worker->pid);
}
LIST_INIT(&orders);
LIST_INIT(&signops);
kore_worker_started();
acme_parse_directory();
while (quit != 1) {
@ -434,7 +430,7 @@ kore_acme_tls_challenge_use_cert(SSL *ssl, struct kore_domain *dom)
return;
}
kore_log(LOG_NOTICE, "[%s] acme-tls/1 challenge requested",
kore_log(LOG_INFO, "[%s] acme-tls/1 challenge requested",
dom->domain);
if ((c = SSL_get_ex_data(ssl, 0)) == NULL)
@ -483,7 +479,7 @@ acme_parse_directory(void)
if (!kore_json_parse(&json)) {
kore_log(LOG_NOTICE,
"failed to parse directory payload from ACME server (%s)",
kore_json_strerror(&json));
kore_json_strerror());
goto cleanup;
}
@ -688,7 +684,7 @@ acme_order_create_submit(struct acme_sign_op *op, struct kore_buf *payload)
if (!kore_json_parse(&json)) {
kore_log(LOG_NOTICE,
"[%s] failed to parse order payload from ACME server (%s)",
domain, kore_json_strerror(&json));
domain, kore_json_strerror());
goto cleanup;
}
@ -806,7 +802,7 @@ acme_order_update_submit(struct acme_sign_op *op, struct kore_buf *payload)
if (!kore_json_parse(&json)) {
kore_log(LOG_NOTICE,
"[%s] failed to parse order payload from ACME server (%s)",
order->domain, kore_json_strerror(&json));
order->domain, kore_json_strerror());
goto cleanup;
}
@ -989,7 +985,7 @@ acme_order_remove(struct acme_order *order, const char *reason)
kore_free(auth);
}
kore_log(LOG_NOTICE, "[%s] order removed (%s)", order->domain, reason);
kore_log(LOG_INFO, "[%s] order removed (%s)", order->domain, reason);
if (strcmp(reason, "completed"))
acme_order_retry(order->domain);
@ -1224,7 +1220,7 @@ acme_order_auth_update_submit(struct acme_sign_op *op, struct kore_buf *payload)
if (!kore_json_parse(&json)) {
kore_log(LOG_NOTICE,
"[%s:auth] failed to parse payload from ACME server (%s)",
order->domain, kore_json_strerror(&json));
order->domain, kore_json_strerror());
goto cleanup;
}
@ -1366,7 +1362,7 @@ cleanup:
} else {
order->auths--;
if (order->auths == 0) {
kore_log(LOG_NOTICE,
kore_log(LOG_INFO,
"[%s:auth] authentications done", order->domain);
order->state = ACME_ORDER_STATE_RUNNING;
}
@ -1389,12 +1385,12 @@ acme_challenge_tls_alpn_01(struct acme_order *order,
acme_challenge_tls_alpn_01_create(order, challenge);
break;
case ACME_STATUS_PROCESSING:
kore_log(LOG_NOTICE,
kore_log(LOG_INFO,
"[%s:auth:challenge:tls-alpn-01] processing",
order->domain);
break;
case ACME_STATUS_VALID:
kore_log(LOG_NOTICE,
kore_log(LOG_INFO,
"[%s:auth:challenge:tls-alpn-01] valid",
order->domain);
ret = KORE_RESULT_OK;
@ -1419,7 +1415,7 @@ acme_challenge_tls_alpn_01_create(struct acme_order *order,
u_int8_t digest[SHA256_DIGEST_LENGTH];
if (challenge->flags & ACME_FLAG_CHALLENGE_CREATED) {
kore_log(LOG_NOTICE,
kore_log(LOG_INFO,
"[%s:auth:challenge:tls-alpn-01] pending keymgr",
order->domain);
return;
@ -1427,7 +1423,7 @@ acme_challenge_tls_alpn_01_create(struct acme_order *order,
challenge->flags |= ACME_FLAG_CHALLENGE_CREATED;
kore_log(LOG_NOTICE,
kore_log(LOG_INFO,
"[%s:auth:challenge:tls-alpn-01] requested from keymgr",
order->domain);

View File

@ -35,7 +35,7 @@ kore_auth_new(const char *name)
{
struct kore_auth *auth;
if ((auth = kore_auth_lookup(name)) != NULL)
if (kore_auth_lookup(name) != NULL)
return (KORE_RESULT_ERROR);
auth = kore_malloc(sizeof(*auth));
@ -90,12 +90,12 @@ kore_auth_run(struct http_request *req, struct kore_auth *auth)
kore_debug("kore_auth_run() for %s failed", req->path);
if (auth->redirect == NULL) {
http_response(req, 403, NULL, 0);
http_response(req, HTTP_STATUS_FORBIDDEN, NULL, 0);
return (KORE_RESULT_ERROR);
}
http_response_header(req, "location", auth->redirect);
http_response(req, 302, NULL, 0);
http_response(req, HTTP_STATUS_FOUND, NULL, 0);
return (KORE_RESULT_ERROR);
}

239
src/cli.c
View File

@ -187,9 +187,12 @@ static void cli_buildopt_kore_flavor(struct buildopt *,
const char *);
static void cli_buildopt_mime(struct buildopt *, const char *);
static void cli_build_flags_common(struct buildopt *,
struct cli_buf *);
static void cli_flavor_load(void);
static void cli_flavor_change(const char *);
static void cli_kore_features(struct buildopt *,
static void cli_kore_load_file(const char *, struct buildopt *,
char **, size_t *);
static void cli_run(int, char **);
@ -200,6 +203,10 @@ static void cli_clean(int, char **);
static void cli_source(int, char **);
static void cli_reload(int, char **);
static void cli_flavor(int, char **);
static void cli_cflags(int, char **);
static void cli_ldflags(int, char **);
static void cli_genasset(int, char **);
static void cli_genasset_help(void);
#if !defined(KODEV_MINIMAL)
static void cli_create(int, char **);
@ -209,7 +216,6 @@ static void file_create_src(void);
static void file_create_config(void);
static void file_create_gitignore(void);
static void file_create_python_src(void);
static void file_create_python_config(void);
static void cli_generate_certs(void);
static void cli_file_create(const char *, const char *, size_t);
@ -218,6 +224,7 @@ static void cli_file_create(const char *, const char *, size_t);
static struct cmd cmds[] = {
{ "help", "this help text", cli_help },
{ "run", "run an application (-fnr implied)", cli_run },
{ "gen", "generate asset file for compilation", cli_genasset },
{ "reload", "reload the application (SIGHUP)", cli_reload },
{ "info", "show info on kore on this system", cli_info },
{ "build", "build an application", cli_build },
@ -227,6 +234,8 @@ static struct cmd cmds[] = {
{ "create", "create a new application skeleton", cli_create },
#endif
{ "flavor", "switch between build flavors", cli_flavor },
{ "cflags", "show kore CFLAGS", cli_cflags },
{ "ldflags", "show kore LDFLAGS", cli_ldflags },
{ NULL, NULL, NULL }
};
@ -253,7 +262,6 @@ static const char *python_gen_dirs[] = {
static struct filegen python_gen_files[] = {
{ file_create_python_src },
{ file_create_python_config },
{ file_create_gitignore },
{ NULL }
};
@ -289,15 +297,16 @@ static const char *config_data =
"\n"
"load\t\t./%s.so\n"
"\n"
"tls_dhparam\tdh2048.pem\n"
"\n"
"domain * {\n"
"\tattach\t\ttls\n"
"\n"
"\tcertfile\tcert/server.pem\n"
"\tcertkey\t\tcert/key.pem\n"
"\n"
"\troute\t/\tpage\n"
"\troute / {\n"
"\t\thandler page\n"
"\t}\n"
"\n"
"}\n";
static const char *build_data =
@ -336,51 +345,29 @@ static const char *build_data =
"# included if you build with the \"prod\" flavor.\n"
"#}\n";
static const char *python_config_data =
"# %s configuration\n"
"\n"
"server tls {\n"
"\tbind 127.0.0.1 8888\n"
"}\n"
"tls_dhparam\tdh2048.pem\n"
"\n"
"domain * {\n"
"\tattach\t\ttls\n"
"\n"
"\tcertfile\tcert/server.pem\n"
"\tcertkey\t\tcert/key.pem\n"
"\n"
"\troute\t/\tkoreapp.index\n"
"}\n";
static const char *python_init_data =
"from .app import koreapp\n";
static const char *python_app_data =
"import kore\n"
"\n"
"class App:\n"
" def __init__(self):\n"
" pass\n"
"\n"
"class KoreApp:\n"
" def configure(self, args):\n"
" kore.config.file = \"kore.conf\"\n"
" kore.config.deployment = \"development\"\n"
" kore.server(\"default\", ip=\"127.0.0.1\", port=\"8888\")\n"
"\n"
" d = kore.domain(\"*\",\n"
" attach=\"default\",\n"
" key=\"cert/key.pem\",\n"
" cert=\"cert/server.pem\",\n"
" )\n"
"\n"
" d.route(\"/\", self.index, methods=[\"get\"])\n"
"\n"
" async def index(self, req):\n"
" req.response(200, b'')\n"
"\n"
"koreapp = App()";
static const char *dh2048_data =
"-----BEGIN DH PARAMETERS-----\n"
"MIIBCAKCAQEAn4f4Qn5SudFjEYPWTbUaOTLUH85YWmmPFW1+b5bRa9ygr+1wfamv\n"
"VKVT7jO8c4msSNikUf6eEfoH0H4VTCaj+Habwu+Sj+I416r3mliMD4SjNsUJrBrY\n"
"Y0QV3ZUgZz4A8ARk/WwQcRl8+ZXJz34IaLwAcpyNhoV46iHVxW0ty8ND0U4DIku/\n"
"PNayKimu4BXWXk4RfwNVP59t8DQKqjshZ4fDnbotskmSZ+e+FHrd+Kvrq/WButvV\n"
"Bzy9fYgnUlJ82g/bziCI83R2xAdtH014fR63MpElkqdNeChb94pPbEdFlNUvYIBN\n"
"xx2vTUQMqRbB4UdG2zuzzr5j98HDdblQ+wIBAg==\n"
"-----END DH PARAMETERS-----";
"koreapp = KoreApp()";
static const char *gitignore = "*.o\n.flavor\n.objs\n%s.so\nassets.h\ncert\n";
@ -400,6 +387,7 @@ static int source_files_count;
static int cxx_files_count;
static struct cmd *command = NULL;
static int cflags_count = 0;
static int genasset_cmd = 0;
static int cxxflags_count = 0;
static int ldflags_count = 0;
static char *flavor = NULL;
@ -546,8 +534,7 @@ cli_create(int argc, char **argv)
cli_generate_certs();
printf("%s created successfully!\n", appl);
printf("WARNING: DO NOT USE THE GENERATED DH PARAMETERS "
"AND CERTIFICATES IN PRODUCTION\n");
printf("WARNING: DO NOT USE THE GENERATED CERTIFICATE IN PRODUCTION\n");
}
#endif
@ -742,9 +729,9 @@ cli_build(int argc, char **argv)
if (bopt->single_binary) {
requires_relink++;
(void)cli_vasprintf(&sofile, "%s", appl);
(void)cli_vasprintf(&sofile, "%s/%s", out_dir, appl);
} else {
(void)cli_vasprintf(&sofile, "%s.so", appl);
(void)cli_vasprintf(&sofile, "%s/%s.so", out_dir, appl);
}
if (!cli_file_exists(sofile) && source_files_count > 0)
@ -772,7 +759,8 @@ cli_source(int argc, char **argv)
static void
cli_clean(int argc, char **argv)
{
char pwd[PATH_MAX], *sofile;
struct buildopt *bopt;
char pwd[PATH_MAX], *bin;
if (cli_dir_exists(object_dir))
cli_cleanup_files(object_dir);
@ -781,11 +769,23 @@ cli_clean(int argc, char **argv)
fatal("could not get cwd: %s", errno_s);
appl = basename(pwd);
(void)cli_vasprintf(&sofile, "%s.so", appl);
if (unlink(sofile) == -1 && errno != ENOENT)
printf("couldn't unlink %s: %s", sofile, errno_s);
free(sofile);
TAILQ_INIT(&mime_types);
TAILQ_INIT(&build_options);
cli_flavor_load();
bopt = cli_buildopt_new("_default");
cli_buildopt_parse("conf/build.conf");
if (bopt->single_binary)
(void)cli_vasprintf(&bin, "%s/%s", out_dir, appl);
else
(void)cli_vasprintf(&bin, "%s/%s.so", out_dir, appl);
if (unlink(bin) == -1 && errno != ENOENT)
printf("couldn't unlink %s: %s", bin, errno_s);
free(bin);
}
static void
@ -853,13 +853,101 @@ cli_info(int argc, char **argv)
printf("kore features\t %s\n", bopt->kore_flavor);
printf("kore source \t %s\n", bopt->kore_source);
} else {
cli_kore_features(bopt, &features, &len);
cli_kore_load_file("features", bopt, &features, &len);
printf("kore binary \t %s/bin/kore\n", prefix);
printf("kore features\t %.*s\n", (int)len, features);
free(features);
}
}
static void
cli_cflags(int argc, char **argv)
{
struct cli_buf *buf;
buf = cli_buf_alloc(128);
cli_build_flags_common(NULL, buf);
printf("%.*s\n", (int)buf->offset, buf->data);
cli_buf_free(buf);
}
static void
cli_ldflags(int argc, char **argv)
{
char *p;
size_t len;
cli_kore_load_file("linker", NULL, &p, &len);
printf("%.*s ", (int)len, p);
#if defined(__MACH__)
printf("-dynamiclib -undefined suppress -flat_namespace ");
#else
printf("-shared ");
#endif
printf("\n");
free(p);
}
static void
cli_genasset(int argc, char **argv)
{
struct stat st;
struct dirent dp;
char *hdr;
genasset_cmd = 1;
TAILQ_INIT(&build_options);
(void)cli_buildopt_new("_default");
if (getenv("KORE_OBJDIR") == NULL)
object_dir = out_dir;
if (argv[0] == NULL)
cli_genasset_help();
(void)cli_vasprintf(&hdr, "%s/assets.h", out_dir);
(void)unlink(hdr);
cli_file_open(hdr, O_CREAT | O_TRUNC | O_WRONLY, &s_fd);
cli_file_writef(s_fd, "#ifndef __H_KORE_ASSETS_H\n");
cli_file_writef(s_fd, "#define __H_KORE_ASSETS_H\n");
if (stat(argv[0], &st) == -1)
fatal("%s: %s", argv[0], errno_s);
if (S_ISDIR(st.st_mode)) {
if (cli_dir_exists(argv[0]))
cli_find_files(argv[0], cli_build_asset);
} else if (S_ISREG(st.st_mode)) {
memset(&dp, 0, sizeof(dp));
dp.d_type = DT_REG;
(void)snprintf(dp.d_name, sizeof(dp.d_name), "%s",
basename(argv[0]));
cli_build_asset(argv[0], &dp);
} else {
fatal("%s is not a directory or regular file", argv[0]);
}
cli_file_writef(s_fd, "\n#endif\n");
cli_file_close(s_fd);
}
static void
cli_genasset_help(void)
{
printf("Usage: kodev genasset [source]\n");
printf("Synopsis:\n");
printf(" Generates asset file(s) to be used for compilation.\n");
printf(" The source can be a single file or directory.\n");
printf("\n");
printf("This command honors the KODEV_OUTPUT environment variable.\n");
printf("This command honors the KORE_OBJDIR environment variable.\n");
exit(1);
}
#if !defined(KODEV_MINIMAL)
static void
file_create_python_src(void)
@ -875,19 +963,6 @@ file_create_python_src(void)
free(name);
}
static void
file_create_python_config(void)
{
int l;
char *name, *data;
(void)cli_vasprintf(&name, "%s/kore.conf", appl);
l = cli_vasprintf(&data, python_config_data, appl);
cli_file_create(name, data, l);
free(name);
free(data);
}
static void
file_create_src(void)
{
@ -1257,7 +1332,9 @@ cli_build_asset(char *fpath, struct dirent *dp)
*--ext = '.';
/* Register the .c file now (cpath is free'd later). */
if (genasset_cmd == 0)
cli_add_source_file(name, cpath, opath, &st, BUILD_C);
free(name);
}
@ -1396,9 +1473,6 @@ cli_generate_certs(void)
RSA *kpair;
char issuer[64];
/* Write out DH parameters. */
cli_file_create("dh2048.pem", dh2048_data, strlen(dh2048_data));
/* Create new certificate. */
if ((x509 = X509_new()) == NULL)
fatal("X509_new(): %s", ssl_errno_s);
@ -1616,10 +1690,8 @@ cli_run_kore_python(void)
fatal("could not get cwd: %s", errno_s);
args[0] = cmd;
args[1] = "-frnc";
args[2] = "kore.conf";
args[3] = pwd;
args[4] = NULL;
args[1] = pwd;
args[2] = NULL;
execvp(args[0], args);
fatal("failed to start '%s': %s", args[0], errno_s);
@ -1935,20 +2007,18 @@ cli_build_flags_common(struct buildopt *bopt, struct cli_buf *buf)
size_t len;
char *data;
cli_buf_appendf(buf, "-fPIC -Isrc -Isrc/includes ");
cli_buf_appendf(buf, "-fPIC ");
if (bopt->single_binary == 0)
if (bopt != NULL)
cli_buf_appendf(buf, "-Isrc -Isrc/includes ");
if (bopt == NULL || bopt->single_binary == 0)
cli_buf_appendf(buf, "-I%s/include ", prefix);
else
cli_buf_appendf(buf, "-I%s/include ", bopt->kore_source);
#if defined(__MACH__)
/* Add default openssl include path from homebrew / ports under OSX. */
cli_buf_appendf(buf, "-I/opt/local/include ");
cli_buf_appendf(buf, "-I/usr/local/opt/openssl/include ");
#endif
if (bopt->single_binary == 0) {
cli_kore_features(bopt, &data, &len);
if (bopt == NULL || bopt->single_binary == 0) {
cli_kore_load_file("features", bopt, &data, &len);
cli_buf_append(buf, data, len);
cli_buf_appendf(buf, " ");
free(data);
@ -1976,7 +2046,7 @@ cli_build_cflags(struct buildopt *bopt)
}
if (bopt->single_binary) {
cli_kore_features(bopt, &buf, &len);
cli_kore_load_file("features", bopt, &buf, &len);
cli_buf_append(bopt->cflags, buf, len);
cli_buf_appendf(bopt->cflags, " ");
free(buf);
@ -2106,16 +2176,17 @@ cli_flavor_load(void)
}
static void
cli_kore_features(struct buildopt *bopt, char **out, size_t *outlen)
cli_kore_load_file(const char *name, struct buildopt *bopt,
char **out, size_t *outlen)
{
int fd;
size_t len;
char *path, *data;
if (bopt->single_binary) {
(void)cli_vasprintf(&path, "%s/features", object_dir);
if (bopt != NULL && bopt->single_binary) {
(void)cli_vasprintf(&path, "%s/%s", object_dir, name);
} else {
(void)cli_vasprintf(&path, "%s/share/kore/features", prefix);
(void)cli_vasprintf(&path, "%s/share/kore/%s", prefix, name);
}
cli_file_open(path, O_RDONLY, &fd);
@ -2124,7 +2195,7 @@ cli_kore_features(struct buildopt *bopt, char **out, size_t *outlen)
free(path);
if (len == 0)
fatal("features is empty");
fatal("%s is empty", name);
len--;

File diff suppressed because it is too large Load Diff

View File

@ -258,6 +258,12 @@ kore_connection_handle(struct connection *c)
switch (c->state) {
case CONN_STATE_TLS_SHAKE:
if (primary_dom == NULL) {
kore_log(LOG_NOTICE,
"TLS handshake but no TLS configured on server");
return (KORE_RESULT_ERROR);
}
if (primary_dom->ssl_ctx == NULL) {
kore_log(LOG_NOTICE,
"TLS configuration for %s not yet complete",

View File

@ -407,18 +407,17 @@ kore_curl_http_setup(struct kore_curl *client, int method, const void *data,
switch (method) {
case HTTP_METHOD_GET:
case HTTP_METHOD_OPTIONS:
break;
case HTTP_METHOD_HEAD:
curl_easy_setopt(client->handle, CURLOPT_NOBODY, 1);
break;
case HTTP_METHOD_DELETE:
case HTTP_METHOD_OPTIONS:
break;
case HTTP_METHOD_PUT:
has_body = 1;
curl_easy_setopt(client->handle, CURLOPT_UPLOAD, 1);
break;
case HTTP_METHOD_PATCH:
case HTTP_METHOD_DELETE:
mname = http_method_text(method);
/* fallthrough */
case HTTP_METHOD_POST:

View File

@ -14,12 +14,6 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* XXX - Lots of OPENSSL ifdefs here for 1.0.2 and 1.1.0 release lines.
* The idea is to only support 1.1.1 down the line and remove the rest.
* (although we have to remain compat with 1.0.2 due to LibreSSL).
*/
#include <sys/param.h>
#include <sys/types.h>
@ -68,54 +62,8 @@ static int keymgr_rsa_privenc(int, const unsigned char *,
static ECDSA_SIG *keymgr_ecdsa_sign(const unsigned char *, int,
const BIGNUM *, const BIGNUM *, EC_KEY *);
#if defined(KORE_OPENSSL_NEWER_API)
static RSA_METHOD *keymgr_rsa_meth = NULL;
static EC_KEY_METHOD *keymgr_ec_meth = NULL;
#else
/*
* Run own ecdsa_method data structure as OpenSSL has this in ecs_locl.h
* and does not export this on systems.
*/
struct ecdsa_method {
const char *name;
ECDSA_SIG *(*ecdsa_do_sign)(const unsigned char *,
int, const BIGNUM *, const BIGNUM *, EC_KEY *);
int (*ecdsa_sign_setup)(EC_KEY *, BN_CTX *, BIGNUM **,
BIGNUM **);
int (*ecdsa_do_verify)(const unsigned char *, int,
const ECDSA_SIG *, EC_KEY *);
int flags;
char *app_data;
};
#endif
#if !defined(KORE_OPENSSL_NEWER_API)
static ECDSA_METHOD keymgr_ecdsa = {
"kore ECDSA keymgr method",
keymgr_ecdsa_sign,
NULL,
NULL,
0,
NULL
};
static RSA_METHOD keymgr_rsa = {
"kore RSA keymgr method",
NULL,
NULL,
keymgr_rsa_privenc,
NULL,
NULL,
NULL,
keymgr_rsa_init,
keymgr_rsa_finish,
RSA_METHOD_FLAG_NO_CHECK,
NULL,
NULL,
NULL,
NULL
};
#endif
static u_int16_t domain_id = 0;
static struct kore_domain *cached[KORE_DOMAIN_CACHE];
@ -128,7 +76,6 @@ kore_domain_init(void)
for (i = 0; i < KORE_DOMAIN_CACHE; i++)
cached[i] = NULL;
#if defined(KORE_OPENSSL_NEWER_API)
if (keymgr_rsa_meth == NULL) {
if ((keymgr_rsa_meth = RSA_meth_new("kore RSA keymgr method",
RSA_METHOD_FLAG_NO_CHECK)) == NULL)
@ -145,7 +92,6 @@ kore_domain_init(void)
}
EC_KEY_METHOD_set_sign(keymgr_ec_meth, NULL, NULL, keymgr_ecdsa_sign);
#endif
#if !defined(TLS1_3_VERSION)
if (!kore_quiet) {
@ -159,7 +105,6 @@ kore_domain_init(void)
void
kore_domain_cleanup(void)
{
#if defined(KORE_OPENSSL_NEWER_API)
if (keymgr_rsa_meth != NULL) {
RSA_meth_free(keymgr_rsa_meth);
keymgr_rsa_meth = NULL;
@ -169,7 +114,6 @@ kore_domain_cleanup(void)
EC_KEY_METHOD_free(keymgr_ec_meth);
keymgr_ec_meth = NULL;
}
#endif
}
struct kore_domain *
@ -187,8 +131,8 @@ kore_domain_new(const char *domain)
dom->domain = kore_strdup(domain);
#if !defined(KORE_NO_HTTP)
TAILQ_INIT(&(dom->handlers));
TAILQ_INIT(&(dom->redirects));
TAILQ_INIT(&dom->routes);
TAILQ_INIT(&dom->redirects);
#endif
if (dom->id < KORE_DOMAIN_CACHE) {
@ -230,8 +174,8 @@ void
kore_domain_free(struct kore_domain *dom)
{
#if !defined(KORE_NO_HTTP)
struct kore_route *rt;
struct http_redirect *rdr;
struct kore_module_handle *hdlr;
#endif
if (dom == NULL)
return;
@ -246,20 +190,17 @@ kore_domain_free(struct kore_domain *dom)
if (dom->ssl_ctx != NULL)
SSL_CTX_free(dom->ssl_ctx);
if (dom->cafile != NULL)
kore_free(dom->cafile);
if (dom->certkey != NULL)
kore_free(dom->certkey);
if (dom->certfile != NULL)
kore_free(dom->certfile);
if (dom->crlfile != NULL)
kore_free(dom->crlfile);
#if !defined(KORE_NO_HTTP)
/* Drop all handlers associated with this domain */
while ((hdlr = TAILQ_FIRST(&(dom->handlers))) != NULL) {
TAILQ_REMOVE(&(dom->handlers), hdlr, list);
kore_module_handler_free(hdlr);
while ((rt = TAILQ_FIRST(&dom->routes)) != NULL) {
TAILQ_REMOVE(&dom->routes, rt, list);
kore_route_free(rt);
}
while ((rdr = TAILQ_FIRST(&(dom->redirects))) != NULL) {
@ -283,35 +224,18 @@ kore_domain_tlsinit(struct kore_domain *dom, int type,
STACK_OF(X509_NAME) *certs;
EC_KEY *eckey;
const SSL_METHOD *method;
#if !defined(KORE_OPENSSL_NEWER_API)
EC_KEY *ecdh;
#endif
kore_debug("kore_domain_tlsinit(%s)", dom->domain);
if (dom->ssl_ctx != NULL)
SSL_CTX_free(dom->ssl_ctx);
#if defined(KORE_OPENSSL_NEWER_API)
if ((method = TLS_method()) == NULL)
fatalx("TLS_method(): %s", ssl_errno_s);
#else
switch (tls_version) {
case KORE_TLS_VERSION_1_3:
case KORE_TLS_VERSION_1_2:
case KORE_TLS_VERSION_BOTH:
method = TLSv1_2_server_method();
break;
default:
fatalx("unknown tls_version: %d", tls_version);
return;
}
#endif
if ((dom->ssl_ctx = SSL_CTX_new(method)) == NULL)
fatalx("SSL_ctx_new(): %s", ssl_errno_s);
#if defined(KORE_OPENSSL_NEWER_API)
if (!SSL_CTX_set_min_proto_version(dom->ssl_ctx, TLS1_2_VERSION))
fatalx("SSL_CTX_set_min_proto_version: %s", ssl_errno_s);
@ -346,7 +270,6 @@ kore_domain_tlsinit(struct kore_domain *dom, int type,
fatalx("unknown tls_version: %d", tls_version);
return;
}
#endif
switch (type) {
case KORE_PEM_CERT_CHAIN:
@ -380,22 +303,13 @@ kore_domain_tlsinit(struct kore_domain *dom, int type,
if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL)
fatalx("no RSA public key present");
RSA_set_app_data(rsa, dom);
#if defined(KORE_OPENSSL_NEWER_API)
RSA_set_method(rsa, keymgr_rsa_meth);
#else
RSA_set_method(rsa, &keymgr_rsa);
#endif
break;
case EVP_PKEY_EC:
if ((eckey = EVP_PKEY_get1_EC_KEY(pkey)) == NULL)
fatalx("no EC public key present");
#if defined(KORE_OPENSSL_NEWER_API)
EC_KEY_set_ex_data(eckey, 0, dom);
EC_KEY_set_method(eckey, keymgr_ec_meth);
#else
ECDSA_set_ex_data(eckey, 0, dom);
ECDSA_set_method(eckey, &keymgr_ecdsa);
#endif
break;
default:
fatalx("unknown public key in certificate");
@ -410,21 +324,13 @@ kore_domain_tlsinit(struct kore_domain *dom, int type,
}
if (tls_dhparam == NULL)
fatalx("No DH parameters given");
fatal("no DH parameters specified");
SSL_CTX_set_tmp_dh(dom->ssl_ctx, tls_dhparam);
SSL_CTX_set_options(dom->ssl_ctx, SSL_OP_SINGLE_DH_USE);
#if defined(KORE_OPENSSL_NEWER_API)
if (!SSL_CTX_set_ecdh_auto(dom->ssl_ctx, 1))
fatalx("SSL_CTX_set_ecdh_auto: %s", ssl_errno_s);
#else
if ((ecdh = EC_KEY_new_by_curve_name(NID_secp384r1)) == NULL)
fatalx("EC_KEY_new_by_curve_name: %s", ssl_errno_s);
SSL_CTX_set_tmp_ecdh(dom->ssl_ctx, ecdh);
EC_KEY_free(ecdh);
#endif
SSL_CTX_set_options(dom->ssl_ctx, SSL_OP_SINGLE_ECDH_USE);
SSL_CTX_set_options(dom->ssl_ctx, SSL_OP_NO_COMPRESSION);
@ -605,27 +511,17 @@ keymgr_init(void)
if ((meth = RSA_get_default_method()) == NULL)
fatal("failed to obtain RSA method");
#if defined(KORE_OPENSSL_NEWER_API)
RSA_meth_set_pub_enc(keymgr_rsa_meth, RSA_meth_get_pub_enc(meth));
RSA_meth_set_pub_dec(keymgr_rsa_meth, RSA_meth_get_pub_dec(meth));
RSA_meth_set_bn_mod_exp(keymgr_rsa_meth, RSA_meth_get_bn_mod_exp(meth));
#else
keymgr_rsa.rsa_pub_enc = meth->rsa_pub_enc;
keymgr_rsa.rsa_pub_dec = meth->rsa_pub_dec;
keymgr_rsa.bn_mod_exp = meth->bn_mod_exp;
#endif
}
static int
keymgr_rsa_init(RSA *rsa)
{
if (rsa != NULL) {
#if defined(KORE_OPENSSL_NEWER_API)
RSA_set_flags(rsa, RSA_flags(rsa) |
RSA_FLAG_EXT_PKEY | RSA_METHOD_FLAG_NO_CHECK);
#else
rsa->flags |= RSA_FLAG_EXT_PKEY | RSA_METHOD_FLAG_NO_CHECK;
#endif
return (1);
}
@ -702,13 +598,8 @@ keymgr_ecdsa_sign(const unsigned char *dgst, int dgst_len,
if (len > sizeof(keymgr_buf))
fatal("keymgr_buf too small");
#if defined(KORE_OPENSSL_NEWER_API)
if ((dom = EC_KEY_get_ex_data(eckey, 0)) == NULL)
fatal("EC_KEY has no domain");
#else
if ((dom = ECDSA_get_ex_data(eckey, 0)) == NULL)
fatal("EC_KEY has no domain");
#endif
memset(keymgr_buf, 0, sizeof(keymgr_buf));
req = (struct kore_keyreq *)keymgr_buf;
@ -890,23 +781,13 @@ domain_load_certificate_chain(SSL_CTX *ctx, const void *data, size_t len)
if (SSL_CTX_use_certificate(ctx, x) == 0)
return (NULL);
#if defined(KORE_OPENSSL_NEWER_API)
SSL_CTX_clear_chain_certs(ctx);
#else
sk_X509_pop_free(ctx->extra_certs, X509_free);
ctx->extra_certs = NULL;
#endif
ERR_clear_error();
while ((ca = PEM_read_bio_X509(in, NULL, NULL, NULL)) != NULL) {
/* ca its reference count won't be increased. */
#if defined(KORE_OPENSSL_NEWER_API)
if (SSL_CTX_add0_chain_cert(ctx, ca) == 0)
return (NULL);
#else
if (SSL_CTX_add_extra_chain_cert(ctx, ca) == 0)
return (NULL);
#endif
}
err = ERR_peek_last_error();

View File

@ -58,7 +58,7 @@ kore_filemap_create(struct kore_domain *dom, const char *path, const char *root)
size_t sz;
struct stat st;
int len;
struct kore_module_handle *hdlr;
struct kore_route *rt;
struct filemap_entry *entry;
char regex[1024], fpath[PATH_MAX];
@ -69,9 +69,9 @@ kore_filemap_create(struct kore_domain *dom, const char *path, const char *root)
if (root[0] != '/' || root[sz - 1] != '/')
return (KORE_RESULT_ERROR);
if (kore_root_path != NULL) {
if (worker_privsep.root != NULL) {
len = snprintf(fpath, sizeof(fpath), "%s/%s",
kore_root_path, path);
worker_privsep.root, path);
if (len == -1 || (size_t)len >= sizeof(fpath))
fatal("kore_filemap_create: failed to concat paths");
} else {
@ -79,27 +79,21 @@ kore_filemap_create(struct kore_domain *dom, const char *path, const char *root)
fatal("kore_filemap_create: failed to copy path");
}
if (stat(fpath, &st) == -1)
if (stat(fpath, &st) == -1) {
kore_log(LOG_ERR, "%s: failed to stat '%s': %s", __func__,
fpath, errno_s);
return (KORE_RESULT_ERROR);
}
len = snprintf(regex, sizeof(regex), "^%s.*$", root);
if (len == -1 || (size_t)len >= sizeof(regex))
fatal("kore_filemap_create: buffer too small");
if (!kore_module_handler_new(dom, regex, "filemap_resolve",
NULL, HANDLER_TYPE_DYNAMIC))
if ((rt = kore_route_create(dom, regex, HANDLER_TYPE_DYNAMIC)) == NULL)
return (KORE_RESULT_ERROR);
hdlr = NULL;
TAILQ_FOREACH(hdlr, &dom->handlers, list) {
if (!strcmp(hdlr->path, regex))
break;
}
if (hdlr == NULL)
fatal("couldn't find newly created handler for filemap");
hdlr->methods = HTTP_METHOD_GET | HTTP_METHOD_HEAD;
kore_route_callback(rt, "filemap_resolve");
rt->methods = HTTP_METHOD_GET | HTTP_METHOD_HEAD;
entry = kore_calloc(1, sizeof(*entry));
entry->domain = dom;
@ -151,7 +145,7 @@ filemap_resolve(struct http_request *req)
best_len = 0;
TAILQ_FOREACH(entry, &maps, list) {
if (entry->domain != req->hdlr->dom)
if (entry->domain != req->rt->dom)
continue;
if (!strncmp(entry->root, req->path, entry->root_len)) {

View File

@ -79,7 +79,7 @@ kore_fileref_create(struct kore_server *srv, const char *path, int fd,
if (srv->tls == 0) {
ref->fd = fd;
} else {
if ((uintmax_t)size> SIZE_MAX) {
if ((uintmax_t)size > SIZE_MAX) {
kore_pool_put(&ref_pool, ref);
return (NULL);
}

1753
src/http.c

File diff suppressed because it is too large Load Diff

View File

@ -49,6 +49,8 @@ static u_int8_t json_null_literal[] = { 'n', 'u', 'l', 'l' };
static u_int8_t json_true_literal[] = { 't', 'r', 'u', 'e' };
static u_int8_t json_false_literal[] = { 'f', 'a', 'l', 's', 'e' };
static int json_errno = 0;
static const char *json_errtab[] = {
"no error",
"invalid JSON object",
@ -84,8 +86,10 @@ kore_json_parse(struct kore_json *json)
if (json->root)
return (KORE_RESULT_OK);
json_errno = 0;
if (json_consume_whitespace(json) == -1) {
json->error = KORE_JSON_ERR_INVALID_JSON;
json_errno = KORE_JSON_ERR_INVALID_JSON;
return (KORE_RESULT_ERROR);
}
@ -93,22 +97,22 @@ kore_json_parse(struct kore_json *json)
return (KORE_RESULT_ERROR);
if (!json_guess_type(ch, &type)) {
json->error = KORE_JSON_ERR_INVALID_JSON;
json_errno = KORE_JSON_ERR_INVALID_JSON;
return (KORE_RESULT_ERROR);
}
json->root = json_item_alloc(type, NULL, NULL);
if (!json->root->parse(json, json->root)) {
if (json->error == 0)
json->error = KORE_JSON_ERR_INVALID_JSON;
if (json_errno == 0)
json_errno = KORE_JSON_ERR_INVALID_JSON;
return (KORE_RESULT_ERROR);
}
/* Don't allow garbage at the end. */
(void)json_consume_whitespace(json);
if (json->offset != json->length) {
json->error = KORE_JSON_ERR_INVALID_JSON;
json_errno = KORE_JSON_ERR_INVALID_JSON;
return (KORE_RESULT_ERROR);
}
@ -122,16 +126,21 @@ kore_json_find(struct kore_json_item *root, const char *path, u_int32_t type)
char *copy;
char *tokens[KORE_JSON_DEPTH_MAX + 1];
json_errno = 0;
copy = kore_strdup(path);
if (!kore_split_string(copy, "/", tokens, KORE_JSON_DEPTH_MAX)) {
kore_free(copy);
json_errno = KORE_JSON_ERR_INVALID_SEARCH;
return (NULL);
}
item = json_find_item(root, tokens, type, 0);
kore_free(copy);
if (item == NULL && json_errno == 0)
json_errno = KORE_JSON_ERR_INVALID_SEARCH;
return (item);
}
@ -145,11 +154,17 @@ kore_json_cleanup(struct kore_json *json)
kore_json_item_free(json->root);
}
const char *
kore_json_strerror(struct kore_json *json)
int
kore_json_errno(void)
{
if (json->error >= 0 && json->error <= KORE_JSON_ERR_LAST)
return (json_errtab[json->error]);
return (json_errno);
}
const char *
kore_json_strerror(void)
{
if (json_errno >= 0 && json_errno <= KORE_JSON_ERR_LAST)
return (json_errtab[json_errno]);
return ("unknown JSON error");
}
@ -182,7 +197,7 @@ kore_json_create_item(struct kore_json_item *parent, const char *name,
item->data.number = va_arg(args, double);
break;
case KORE_JSON_TYPE_INTEGER:
item->data.s64 = va_arg(args, int64_t);
item->data.integer = va_arg(args, int64_t);
break;
case KORE_JSON_TYPE_INTEGER_U64:
item->data.u64 = va_arg(args, u_int64_t);
@ -248,7 +263,7 @@ kore_json_item_tobuf(struct kore_json_item *item, struct kore_buf *buf)
kore_buf_appendf(buf, "%f", item->data.number);
break;
case KORE_JSON_TYPE_INTEGER:
kore_buf_appendf(buf, "%" PRId64, item->data.s64);
kore_buf_appendf(buf, "%" PRId64, item->data.integer);
break;
case KORE_JSON_TYPE_INTEGER_U64:
kore_buf_appendf(buf, "%" PRIu64, item->data.u64);
@ -277,6 +292,24 @@ kore_json_item_tobuf(struct kore_json_item *item, struct kore_buf *buf)
}
}
void
kore_json_item_attach(struct kore_json_item *parent,
struct kore_json_item *item)
{
if (item->parent != NULL)
fatal("%s: item already has parent", __func__);
item->parent = parent;
if (parent->type != KORE_JSON_TYPE_OBJECT &&
parent->type != KORE_JSON_TYPE_ARRAY) {
fatal("%s: invalid parent type (%d)",
__func__, parent->type);
}
TAILQ_INSERT_TAIL(&parent->data.items, item, list);
}
static struct kore_json_item *
json_find_item(struct kore_json_item *object, char **tokens,
u_int32_t type, int pos)
@ -321,15 +354,33 @@ json_find_item(struct kore_json_item *object, char **tokens,
break;
}
if (nitem == NULL)
if (nitem == NULL) {
json_errno = KORE_JSON_ERR_NOT_FOUND;
return (NULL);
}
item = nitem;
}
if (tokens[pos + 1] == NULL) {
/*
* If an uint64 was required and we find an item
* with the same name but marked as an integer check
* if it can be represented as a uint64.
*
* If it can, reduce the type to integer so we match
* on it as well.
*/
if (type == KORE_JSON_TYPE_INTEGER_U64 &&
item->type == KORE_JSON_TYPE_INTEGER) {
if (item->data.integer >= 0)
type = KORE_JSON_TYPE_INTEGER;
}
if (item->type == type)
return (item);
json_errno = KORE_JSON_ERR_TYPE_MISMATCH;
return (NULL);
}
@ -343,6 +394,9 @@ json_find_item(struct kore_json_item *object, char **tokens,
break;
}
if (item == NULL && json_errno == 0)
json_errno = KORE_JSON_ERR_NOT_FOUND;
return (item);
}
@ -443,7 +497,7 @@ static int
json_next_byte(struct kore_json *json, u_int8_t *ch, int peek)
{
if (json->offset >= json->length) {
json->error = KORE_JSON_ERR_EOF;
json_errno = KORE_JSON_ERR_EOF;
return (KORE_RESULT_ERROR);
}
@ -513,7 +567,7 @@ json_parse_object(struct kore_json *json, struct kore_json_item *object)
int ret, hasnext;
if (json->depth++ >= KORE_JSON_DEPTH_MAX) {
json->error = KORE_JSON_ERR_DEPTH;
json_errno = KORE_JSON_ERR_DEPTH;
return (KORE_RESULT_ERROR);
}
@ -537,7 +591,7 @@ json_parse_object(struct kore_json *json, struct kore_json_item *object)
switch (ch) {
case '}':
if (hasnext) {
json->error = KORE_JSON_ERR_INVALID_JSON;
json_errno = KORE_JSON_ERR_INVALID_JSON;
goto cleanup;
}
json->offset++;
@ -596,8 +650,8 @@ json_parse_object(struct kore_json *json, struct kore_json_item *object)
}
cleanup:
if (ret == KORE_RESULT_ERROR && json->error == 0)
json->error = KORE_JSON_ERR_INVALID_OBJECT;
if (ret == KORE_RESULT_ERROR && json_errno == 0)
json_errno = KORE_JSON_ERR_INVALID_OBJECT;
json->depth--;
@ -614,7 +668,7 @@ json_parse_array(struct kore_json *json, struct kore_json_item *array)
int ret, hasnext;
if (json->depth++ >= KORE_JSON_DEPTH_MAX) {
json->error = KORE_JSON_ERR_DEPTH;
json_errno = KORE_JSON_ERR_DEPTH;
return (KORE_RESULT_ERROR);
}
@ -637,7 +691,7 @@ json_parse_array(struct kore_json *json, struct kore_json_item *array)
if (ch == ']') {
if (hasnext) {
json->error = KORE_JSON_ERR_INVALID_JSON;
json_errno = KORE_JSON_ERR_INVALID_JSON;
goto cleanup;
}
json->offset++;
@ -675,8 +729,8 @@ json_parse_array(struct kore_json *json, struct kore_json_item *array)
}
cleanup:
if (ret == KORE_RESULT_ERROR && json->error == 0)
json->error = KORE_JSON_ERR_INVALID_ARRAY;
if (ret == KORE_RESULT_ERROR && json_errno == 0)
json_errno = KORE_JSON_ERR_INVALID_ARRAY;
json->depth--;
@ -762,10 +816,14 @@ json_parse_number(struct kore_json *json, struct kore_json_item *number)
kore_strtodouble(str, -DBL_MAX, DBL_MAX, &ret);
break;
case KORE_JSON_TYPE_INTEGER:
number->data.s64 = (int64_t)kore_strtonum64(str, 1, &ret);
number->data.integer = (int64_t)kore_strtonum64(str, 1, &ret);
break;
case KORE_JSON_TYPE_INTEGER_U64:
number->data.s64 = kore_strtonum64(str, 0, &ret);
number->data.u64 = kore_strtonum64(str, 0, &ret);
if (number->data.u64 <= INT64_MAX) {
type = KORE_JSON_TYPE_INTEGER;
number->data.integer = number->data.u64;
}
break;
default:
goto cleanup;
@ -774,8 +832,8 @@ json_parse_number(struct kore_json *json, struct kore_json_item *number)
number->type = type;
cleanup:
if (ret == KORE_RESULT_ERROR && json->error == 0)
json->error = KORE_JSON_ERR_INVALID_NUMBER;
if (ret == KORE_RESULT_ERROR && json_errno == 0)
json_errno = KORE_JSON_ERR_INVALID_NUMBER;
return (ret);
}
@ -826,8 +884,8 @@ json_parse_literal(struct kore_json *json, struct kore_json_item *literal)
ret = KORE_RESULT_OK;
cleanup:
if (ret == KORE_RESULT_ERROR && json->error == 0)
json->error = KORE_JSON_ERR_INVALID_LITERAL;
if (ret == KORE_RESULT_ERROR && json_errno == 0)
json_errno = KORE_JSON_ERR_INVALID_LITERAL;
return (ret);
}
@ -895,8 +953,8 @@ json_get_string(struct kore_json *json)
res = kore_buf_stringify(&json->tmpbuf, NULL);
cleanup:
if (res == NULL && json->error == 0)
json->error = KORE_JSON_ERR_INVALID_STRING;
if (res == NULL && json_errno == 0)
json_errno = KORE_JSON_ERR_INVALID_STRING;
return (res);
}

View File

@ -423,13 +423,13 @@ jsonrpc_error(struct jsonrpc_request *req, int code, const char *msg)
http_response_header(req->http, "content-type", "application/json");
yajl_gen_get_buf(req->gen, &body, &body_len);
succeeded:
http_response(req->http, 200, body, body_len);
http_response(req->http, HTTP_STATUS_OK, body, body_len);
if (req->gen != NULL)
yajl_gen_clear(req->gen);
jsonrpc_destroy_request(req);
return (KORE_RESULT_OK);
failed:
http_response(req->http, 500, NULL, 0);
http_response(req->http, HTTP_STATUS_INTERNAL_ERROR, NULL, 0);
jsonrpc_destroy_request(req);
return (KORE_RESULT_OK);
}
@ -466,13 +466,13 @@ jsonrpc_result(struct jsonrpc_request *req,
http_response_header(req->http, "content-type", "application/json");
yajl_gen_get_buf(req->gen, &body, &body_len);
succeeded:
http_response(req->http, 200, body, body_len);
http_response(req->http, HTTP_STATUS_OK, body, body_len);
if (req->gen != NULL)
yajl_gen_clear(req->gen);
jsonrpc_destroy_request(req);
return (KORE_RESULT_OK);
failed:
http_response(req->http, 500, NULL, 0);
http_response(req->http, HTTP_STATUS_INTERNAL_ERROR, NULL, 0);
jsonrpc_destroy_request(req);
return (KORE_RESULT_OK);
}

View File

@ -87,6 +87,9 @@ static struct sock_filter filter_keymgr[] = {
KORE_SYSCALL_ALLOW(fstat),
#if defined(SYS_fstat64)
KORE_SYSCALL_ALLOW(fstat64),
#endif
#if defined(SYS_newfstatat)
KORE_SYSCALL_ALLOW(newfstatat),
#endif
KORE_SYSCALL_ALLOW(futex),
KORE_SYSCALL_ALLOW(writev),
@ -137,6 +140,9 @@ static struct sock_filter filter_keymgr[] = {
#endif
#if defined(SYS_mmap2)
KORE_SYSCALL_ALLOW(mmap2),
#endif
#if defined(SYS_madvise)
KORE_SYSCALL_ALLOW(madvise),
#endif
KORE_SYSCALL_ALLOW(munmap),
KORE_SYSCALL_ALLOW(clock_gettime),
@ -245,9 +251,8 @@ static void keymgr_rsa_encrypt(struct kore_msg *, const void *,
static void keymgr_ecdsa_sign(struct kore_msg *, const void *,
struct key *);
struct kore_privsep keymgr_privsep;
int keymgr_active = 0;
char *keymgr_root_path = NULL;
char *keymgr_runas_user = NULL;
#if defined(__OpenBSD__)
#if defined(KORE_USE_ACME)
@ -290,10 +295,7 @@ kore_keymgr_run(void)
#if defined(KORE_USE_PYTHON)
kore_msg_unregister(KORE_PYTHON_SEND_OBJ);
#endif
kore_worker_privdrop(keymgr_runas_user, keymgr_root_path);
if (!kore_quiet)
kore_log(LOG_NOTICE, "key manager started (pid#%d)", getpid());
kore_worker_privsep();
if (rand_file != NULL) {
keymgr_load_randfile();
@ -318,6 +320,8 @@ kore_keymgr_run(void)
X509V3_EXT_add_alias(acme_oid, NID_subject_key_identifier);
#endif
kore_worker_started();
while (quit != 1) {
now = kore_time_ms();
if ((now - last_seed) > RAND_POLL_INTERVAL) {
@ -363,9 +367,6 @@ kore_keymgr_cleanup(int final)
{
struct key *key, *next;
if (final && !kore_quiet)
kore_log(LOG_NOTICE, "cleaning up keys");
if (initialized == 0)
return;
@ -574,6 +575,7 @@ keymgr_load_domain_privatekey(struct kore_domain *dom)
key->dom = dom;
if (!kore_quiet)
kore_log(LOG_INFO, "loaded private key for '%s'", dom->domain);
}
@ -690,12 +692,8 @@ keymgr_rsa_encrypt(struct kore_msg *msg, const void *data, struct key *key)
u_int8_t buf[1024];
req = (const struct kore_keyreq *)data;
#if defined(KORE_OPENSSL_NEWER_API)
rsa = EVP_PKEY_get0_RSA(key->pkey);
#else
rsa = key->pkey->pkey.rsa;
#endif
keylen = RSA_size(rsa);
if (req->data_len > keylen || keylen > sizeof(buf))
return;
@ -718,11 +716,8 @@ keymgr_ecdsa_sign(struct kore_msg *msg, const void *data, struct key *key)
u_int8_t sig[1024];
req = (const struct kore_keyreq *)data;
#if defined(KORE_OPENSSL_NEWER_API)
ec = EVP_PKEY_get0_EC_KEY(key->pkey);
#else
ec = key->pkey->pkey.ec;
#endif
len = ECDSA_size(ec);
if (req->data_len > len || len > sizeof(sig))
return;
@ -791,21 +786,15 @@ keymgr_acme_init(void)
ACME_RENEWAL_TIMER, NULL, 0);
if (key->pkey == NULL) {
kore_log(LOG_NOTICE, "generating new ACME account key");
kore_log(LOG_INFO, "generating new ACME account key");
key->pkey = kore_rsakey_generate(KORE_ACME_ACCOUNT_KEY);
needsreg = 1;
} else {
kore_log(LOG_INFO, "loaded existing ACME account key");
}
#if defined(KORE_OPENSSL_NEWER_API)
rsa = EVP_PKEY_get0_RSA(key->pkey);
RSA_get0_key(rsa, &bn, &be, NULL);
#else
rsa = key->pkey->pkey.rsa;
be = rsa->e;
bn = rsa->n;
#endif
e = keymgr_bignum_base64(be);
n = keymgr_bignum_base64(bn);
@ -837,7 +826,7 @@ keymgr_acme_domainkey(struct kore_domain *dom, struct key *key)
{
char *p;
kore_log(LOG_NOTICE, "generated new domain key for %s", dom->domain);
kore_log(LOG_INFO, "generated new domain key for %s", dom->domain);
if ((p = strrchr(dom->certkey, '/')) == NULL)
fatalx("invalid certkey path '%s'", dom->certkey);
@ -1038,7 +1027,7 @@ keymgr_acme_install_cert(const void *data, size_t len, struct key *key)
fd = open(key->dom->certfile, O_CREAT | O_TRUNC | O_WRONLY, 0700);
if (fd == -1)
fatal("open(%s): %s", key->dom->certfile, errno_s);
fatalx("open(%s): %s", key->dom->certfile, errno_s);
kore_log(LOG_INFO, "writing %zu bytes of data", len);
@ -1047,14 +1036,14 @@ keymgr_acme_install_cert(const void *data, size_t len, struct key *key)
if (ret == -1) {
if (errno == EINTR)
continue;
fatal("write(%s): %s", key->dom->certfile, errno_s);
fatalx("write(%s): %s", key->dom->certfile, errno_s);
}
break;
}
if ((size_t)ret != len) {
fatal("incorrect write on %s (%zd/%zu)",
fatalx("incorrect write on %s (%zd/%zu)",
key->dom->certfile, ret, len);
}
@ -1111,7 +1100,7 @@ keymgr_acme_challenge_cert(const void *data, size_t len, struct key *key)
slen = snprintf(hex + (idx * 2), sizeof(hex) - (idx * 2),
"%02x", digest[idx]);
if (slen == -1 || (size_t)slen >= sizeof(hex))
fatal("failed to convert digest to hex");
fatalx("failed to convert digest to hex");
}
if ((x509 = X509_new()) == NULL)
@ -1185,7 +1174,7 @@ keymgr_acme_csr(const struct kore_keyreq *req, struct key *key)
kore_log(LOG_INFO, "[%s] creating CSR", req->domain);
if ((csr = X509_REQ_new()) == NULL)
fatal("X509_REQ_new: %s", ssl_errno_s);
fatalx("X509_REQ_new: %s", ssl_errno_s);
if (!X509_REQ_set_version(csr, 3))
fatalx("X509_REQ_set_version(): %s", ssl_errno_s);

View File

@ -54,6 +54,7 @@ volatile sig_atomic_t sig_recv;
struct kore_server_list kore_servers;
u_int8_t nlisteners;
int kore_argc = 0;
int kore_quit = 0;
pid_t kore_pid = -1;
u_int16_t cpu_count = 1;
int kore_debug = 0;
@ -64,12 +65,12 @@ u_int8_t worker_count = 0;
char **kore_argv = NULL;
int kore_foreground = 0;
char *kore_progname = NULL;
char *kore_root_path = NULL;
char *kore_runas_user = NULL;
u_int32_t kore_socket_backlog = 5000;
char *kore_pidfile = KORE_PIDFILE_DEFAULT;
char *kore_tls_cipher_list = KORE_DEFAULT_CIPHER_LIST;
struct kore_privsep worker_privsep;
extern char **environ;
extern char *__progname;
static size_t proctitle_maxlen = 0;
@ -80,6 +81,7 @@ static void version(void);
static void kore_write_kore_pid(void);
static void kore_proctitle_setup(void);
static void kore_server_sslstart(void);
static void kore_server_shutdown(void);
static void kore_server_start(int, char *[]);
static void kore_call_parent_configure(int, char **);
@ -113,9 +115,9 @@ usage(void)
#endif
printf("\t-f\tstart in foreground\n");
printf("\t-h\tthis help text\n");
printf("\t-n\tdo not chroot\n");
printf("\t-n\tdo not chroot on any worker\n");
printf("\t-q\tonly log errors\n");
printf("\t-r\tdo not drop privileges\n");
printf("\t-r\tdo not change user on any worker\n");
printf("\t-v\tdisplay %s build information\n", __progname);
printf("\nFind more information on https://kore.io\n");
@ -168,6 +170,9 @@ main(int argc, char *argv[])
#endif
kore_mem_init();
kore_msg_init();
kore_log_init();
kore_progname = kore_strdup(argv[0]);
kore_proctitle_setup();
@ -194,10 +199,6 @@ main(int argc, char *argv[])
if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode))
fatal("%s: not a directory or file", kore_pymodule);
}
#elif !defined(KORE_SINGLE_BINARY)
if (argc > 0)
fatal("did you mean to run `kodev' instead?");
#endif
kore_pid = getpid();
@ -205,8 +206,6 @@ main(int argc, char *argv[])
LIST_INIT(&kore_servers);
kore_platform_init();
kore_log_init();
kore_msg_init();
#if !defined(KORE_NO_HTTP)
http_parent_init();
#if defined(KORE_USE_CURL)
@ -274,11 +273,7 @@ main(int argc, char *argv[])
kore_signal_setup();
kore_server_start(argc, argv);
if (!kore_quiet)
kore_log(LOG_NOTICE, "server shutting down");
kore_worker_shutdown();
kore_server_shutdown();
rcall = kore_runtime_getcall(parent_teardown_hook);
if (rcall != NULL) {
@ -292,7 +287,7 @@ main(int argc, char *argv[])
kore_server_cleanup();
if (!kore_quiet)
kore_log(LOG_NOTICE, "goodbye");
kore_log(LOG_INFO, "goodbye");
#if defined(KORE_USE_PYTHON)
kore_python_cleanup();
@ -497,6 +492,15 @@ kore_server_bind_unix(struct kore_server *srv, const char *path,
if (!kore_listener_init(l, AF_UNIX, ccb))
return (KORE_RESULT_ERROR);
if (sun.sun_path[0] != '\0') {
if (unlink(sun.sun_path) == -1 && errno != ENOENT) {
kore_log(LOG_ERR, "unlink: %s: %s",
sun.sun_path, errno_s);
kore_listener_free(l);
return (KORE_RESULT_ERROR);
}
}
if (bind(l->fd, (struct sockaddr *)&sun, socklen) == -1) {
kore_log(LOG_ERR, "bind: %s", errno_s);
kore_listener_free(l);
@ -545,10 +549,10 @@ kore_server_finalize(struct kore_server *srv)
proto = "http";
if (l->family == AF_UNIX) {
kore_log(LOG_NOTICE, "%s serving %s on %s",
kore_log(LOG_INFO, "%s serving %s on %s",
srv->name, proto, l->host);
} else {
kore_log(LOG_NOTICE, "%s serving %s on %s:%s",
kore_log(LOG_INFO, "%s serving %s on %s:%s",
srv->name, proto, l->host, l->port);
}
}
@ -657,11 +661,30 @@ kore_server_free(struct kore_server *srv)
void
kore_listener_free(struct listener *l)
{
int rm;
LIST_REMOVE(l, list);
if (l->fd != -1)
close(l->fd);
rm = 0;
#if defined(__linux__)
if (worker == NULL && l->family == AF_UNIX && l->host[0] != '@')
rm++;
#else
if (worker == NULL && l->family == AF_UNIX)
rm++;
#endif
if (rm) {
if (unlink(l->host) == -1) {
kore_log(LOG_NOTICE,
"failed to remove unix socket %s (%s)", l->host,
errno_s);
}
}
kore_free(l->host);
kore_free(l->port);
@ -717,6 +740,23 @@ kore_sockopt(int fd, int what, int opt)
void
kore_signal_setup(void)
{
kore_signal_trap(SIGHUP);
kore_signal_trap(SIGQUIT);
kore_signal_trap(SIGTERM);
kore_signal_trap(SIGUSR1);
kore_signal_trap(SIGCHLD);
if (kore_foreground)
kore_signal_trap(SIGINT);
else
(void)signal(SIGINT, SIG_IGN);
(void)signal(SIGPIPE, SIG_IGN);
}
void
kore_signal_trap(int sig)
{
struct sigaction sa;
@ -727,25 +767,8 @@ kore_signal_setup(void)
if (sigfillset(&sa.sa_mask) == -1)
fatal("sigfillset: %s", errno_s);
if (sigaction(SIGHUP, &sa, NULL) == -1)
if (sigaction(sig, &sa, NULL) == -1)
fatal("sigaction: %s", errno_s);
if (sigaction(SIGQUIT, &sa, NULL) == -1)
fatal("sigaction: %s", errno_s);
if (sigaction(SIGTERM, &sa, NULL) == -1)
fatal("sigaction: %s", errno_s);
if (sigaction(SIGUSR1, &sa, NULL) == -1)
fatal("sigaction: %s", errno_s);
if (sigaction(SIGCHLD, &sa, NULL) == -1)
fatal("sigaction: %s", errno_s);
if (kore_foreground) {
if (sigaction(SIGINT, &sa, NULL) == -1)
fatal("sigaction: %s", errno_s);
} else {
(void)signal(SIGINT, SIG_IGN);
}
(void)signal(SIGPIPE, SIG_IGN);
}
void
@ -833,11 +856,39 @@ kore_server_start(int argc, char *argv[])
u_int32_t tmp;
struct kore_server *srv;
u_int64_t netwait;
int quit, last_sig;
int last_sig;
#if defined(KORE_SINGLE_BINARY)
struct kore_runtime_call *rcall;
#endif
if (!kore_quiet) {
kore_log(LOG_INFO, "%s %s starting, built=%s",
__progname, kore_version, kore_build_date);
kore_log(LOG_INFO, "built-ins: "
#if defined(__linux__)
"seccomp "
#endif
#if defined(KORE_USE_PGSQL)
"pgsql "
#endif
#if defined(KORE_USE_TASKS)
"tasks "
#endif
#if defined(KORE_USE_JSONRPC)
"jsonrpc "
#endif
#if defined(KORE_USE_PYTHON)
"python "
#endif
#if defined(KORE_USE_ACME)
"acme "
#endif
#if defined(KORE_USE_CURL)
"curl "
#endif
);
}
if (kore_foreground == 0) {
if (daemon(1, 0) == -1)
fatal("cannot daemon(): %s", errno_s);
@ -853,25 +904,6 @@ kore_server_start(int argc, char *argv[])
kore_pid = getpid();
kore_write_kore_pid();
if (!kore_quiet) {
kore_log(LOG_NOTICE, "%s is starting up", __progname);
#if defined(__linux__)
kore_log(LOG_NOTICE, "seccomp sandbox enabled");
#endif
#if defined(KORE_USE_PGSQL)
kore_log(LOG_NOTICE, "pgsql built-in enabled");
#endif
#if defined(KORE_USE_TASKS)
kore_log(LOG_NOTICE, "tasks built-in enabled");
#endif
#if defined(KORE_USE_JSONRPC)
kore_log(LOG_NOTICE, "jsonrpc built-in enabled");
#endif
#if defined(KORE_USE_PYTHON)
kore_log(LOG_NOTICE, "python built-in enabled");
#endif
}
#if !defined(KORE_SINGLE_BINARY) && !defined(KORE_USE_PYTHON)
kore_call_parent_configure(argc, argv);
#endif
@ -881,6 +913,10 @@ kore_server_start(int argc, char *argv[])
kore_call_parent_configure(argc, argv);
#endif
#if defined(KORE_USE_PYTHON)
kore_python_routes_resolve();
#endif
/* Check if keymgr will be active. */
LIST_FOREACH(srv, &kore_servers, list) {
if (srv->tls) {
@ -890,7 +926,19 @@ kore_server_start(int argc, char *argv[])
}
kore_platform_proctitle("[parent]");
kore_worker_init();
if (!kore_worker_init()) {
kore_log(LOG_ERR, "last worker log lines:");
kore_log(LOG_ERR, "=====================================");
net_init();
kore_connection_init();
kore_platform_event_init();
kore_msg_parent_init();
kore_platform_event_wait(10);
kore_worker_dispatch_signal(SIGQUIT);
kore_log(LOG_ERR, "=====================================");
return;
}
/* Set worker_max_connections for kore_connection_init(). */
tmp = worker_max_connections;
@ -901,7 +949,6 @@ kore_server_start(int argc, char *argv[])
kore_platform_event_init();
kore_msg_parent_init();
quit = 0;
worker_max_connections = tmp;
kore_timer_init();
@ -913,23 +960,23 @@ kore_server_start(int argc, char *argv[])
kore_msg_unregister(KORE_PYTHON_SEND_OBJ);
#endif
while (quit != 1) {
if (sig_recv != 0) {
while (kore_quit != 1) {
last_sig = sig_recv;
switch (sig_recv) {
if (last_sig != 0) {
switch (last_sig) {
case SIGHUP:
kore_worker_dispatch_signal(sig_recv);
kore_worker_dispatch_signal(last_sig);
kore_module_reload(0);
break;
case SIGINT:
case SIGQUIT:
case SIGTERM:
quit = 1;
kore_worker_dispatch_signal(sig_recv);
kore_quit = 1;
kore_worker_dispatch_signal(last_sig);
continue;
case SIGUSR1:
kore_worker_dispatch_signal(sig_recv);
kore_worker_dispatch_signal(last_sig);
break;
case SIGCHLD:
kore_worker_reap();
@ -948,8 +995,20 @@ kore_server_start(int argc, char *argv[])
kore_platform_event_wait(netwait);
kore_connection_prune(KORE_CONNECTION_PRUNE_DISCONNECT);
kore_timer_run(kore_time_ms());
kore_worker_reap();
}
kore_worker_dispatch_signal(SIGQUIT);
}
static void
kore_server_shutdown(void)
{
if (!kore_quiet)
kore_log(LOG_INFO, "server shutting down");
kore_worker_shutdown();
#if !defined(KORE_NO_HTTP)
kore_accesslog_gather(NULL, kore_time_ms(), 1);
#endif

159
src/log.c Normal file
View File

@ -0,0 +1,159 @@
/*
* Copyright (c) 2021 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/types.h>
#include <time.h>
#include <syslog.h>
#include "kore.h"
struct kore_wlog {
int prio;
u_int16_t wid;
size_t loglen;
char logmsg[];
};
static void log_print(int, const char *, ...);
static void log_from_worker(struct kore_msg *, const void *);
static FILE *fp = NULL;
void
kore_log_init(void)
{
#if defined(KORE_SINGLE_BINARY)
extern const char *__progname;
const char *name = kore_strdup(__progname);
#else
const char *name = "kore";
#endif
fp = stdout;
if (!kore_foreground)
openlog(name, LOG_NDELAY | LOG_PID, LOG_DAEMON);
kore_msg_register(KORE_MSG_WORKER_LOG, log_from_worker);
}
void
kore_log_file(const char *path)
{
if ((fp = fopen(path, "a")) == NULL) {
fp = stdout;
fatal("fopen(%s): %s", path, errno_s);
}
}
void
kore_log(int prio, const char *fmt, ...)
{
va_list args;
const char *str;
struct kore_wlog wlog;
struct kore_buf buf, pkt;
kore_buf_init(&buf, 128);
va_start(args, fmt);
kore_buf_appendv(&buf, fmt, args);
va_end(args);
if (worker != NULL) {
kore_buf_init(&pkt, sizeof(wlog) + buf.offset);
memset(&wlog, 0, sizeof(wlog));
wlog.prio = prio;
wlog.wid = worker->id;
wlog.loglen = buf.offset;
kore_buf_append(&pkt, &wlog, sizeof(wlog));
kore_buf_append(&pkt, buf.data, buf.offset);
kore_msg_send(KORE_MSG_PARENT, KORE_MSG_WORKER_LOG,
pkt.data, pkt.offset);
kore_buf_cleanup(&pkt);
} else {
str = kore_buf_stringify(&buf, NULL);
if (kore_foreground || fp != stdout)
log_print(prio, "[parent]: %s\n", str);
else
syslog(prio, "[parent]: %s", str);
}
kore_buf_cleanup(&buf);
}
static void
log_from_worker(struct kore_msg *msg, const void *data)
{
const char *name;
const struct kore_wlog *wlog;
if (msg->length < sizeof(*wlog)) {
kore_log(LOG_NOTICE,
"too short worker log received (%zu < %zu)",
msg->length, sizeof(*wlog));
return;
}
wlog = data;
name = kore_worker_name(wlog->wid);
if (kore_foreground || fp != stdout) {
log_print(wlog->prio, "%s: %.*s\n",
name, (int)wlog->loglen, wlog->logmsg);
} else {
syslog(wlog->prio, "%s: %.*s",
name, (int)wlog->loglen, wlog->logmsg);
}
}
static void
log_print(int prio, const char *fmt, ...)
{
struct tm *t;
struct timespec ts;
va_list args;
char tbuf[32];
va_start(args, fmt);
switch (prio) {
case LOG_ERR:
case LOG_WARNING:
case LOG_NOTICE:
case LOG_INFO:
case LOG_DEBUG:
break;
}
(void)clock_gettime(CLOCK_REALTIME, &ts);
t = gmtime(&ts.tv_sec);
if (strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %H:%M:%S", t) > 0)
fprintf(fp, "%s.%03ld UTC ", tbuf, ts.tv_nsec / 1000000);
vfprintf(fp, fmt, args);
fflush(fp);
va_end(args);
}

View File

@ -135,11 +135,6 @@ kore_module_reload(int cbs)
{
struct stat st;
int ret;
#if !defined(KORE_NO_HTTP)
struct kore_server *srv;
struct kore_domain *dom;
struct kore_module_handle *hdlr;
#endif
struct kore_module *module;
TAILQ_FOREACH(module, &modules, list) {
@ -183,22 +178,7 @@ kore_module_reload(int cbs)
}
#if !defined(KORE_NO_HTTP)
LIST_FOREACH(srv, &kore_servers, list) {
TAILQ_FOREACH(dom, &srv->domains, list) {
TAILQ_FOREACH(hdlr, &(dom->handlers), list) {
kore_free(hdlr->rcall);
hdlr->rcall = kore_runtime_getcall(hdlr->func);
if (hdlr->rcall == NULL) {
fatal("no function '%s' found",
hdlr->func);
}
hdlr->errors = 0;
}
}
}
#endif
#if !defined(KORE_NO_HTTP)
kore_route_reload();
kore_validator_reload();
#endif
}
@ -212,97 +192,6 @@ kore_module_loaded(void)
return (1);
}
#if !defined(KORE_NO_HTTP)
int
kore_module_handler_new(struct kore_domain *dom, const char *path,
const char *func, const char *auth, int type)
{
struct kore_auth *ap;
struct kore_module_handle *hdlr;
if (auth != NULL) {
if ((ap = kore_auth_lookup(auth)) == NULL)
fatal("no authentication block '%s' found", auth);
} else {
ap = NULL;
}
hdlr = kore_malloc(sizeof(*hdlr));
hdlr->auth = ap;
hdlr->dom = dom;
hdlr->errors = 0;
hdlr->type = type;
hdlr->path = kore_strdup(path);
hdlr->func = kore_strdup(func);
hdlr->methods = HTTP_METHOD_ALL;
TAILQ_INIT(&(hdlr->params));
if ((hdlr->rcall = kore_runtime_getcall(func)) == NULL) {
kore_module_handler_free(hdlr);
kore_log(LOG_ERR, "function '%s' not found", func);
return (KORE_RESULT_ERROR);
}
if (hdlr->type == HANDLER_TYPE_DYNAMIC) {
if (regcomp(&(hdlr->rctx), hdlr->path,
REG_EXTENDED | REG_NOSUB)) {
kore_module_handler_free(hdlr);
kore_debug("regcomp() on %s failed", path);
return (KORE_RESULT_ERROR);
}
}
TAILQ_INSERT_TAIL(&(dom->handlers), hdlr, list);
return (KORE_RESULT_OK);
}
void
kore_module_handler_free(struct kore_module_handle *hdlr)
{
struct kore_handler_params *param;
if (hdlr == NULL)
return;
if (hdlr->func != NULL)
kore_free(hdlr->func);
if (hdlr->path != NULL)
kore_free(hdlr->path);
if (hdlr->type == HANDLER_TYPE_DYNAMIC)
regfree(&(hdlr->rctx));
/* Drop all validators associated with this handler */
while ((param = TAILQ_FIRST(&(hdlr->params))) != NULL) {
TAILQ_REMOVE(&(hdlr->params), param, list);
if (param->name != NULL)
kore_free(param->name);
kore_free(param);
}
kore_free(hdlr);
}
struct kore_module_handle *
kore_module_handler_find(struct http_request *req, struct kore_domain *dom)
{
struct kore_module_handle *hdlr;
TAILQ_FOREACH(hdlr, &(dom->handlers), list) {
if (hdlr->type == HANDLER_TYPE_STATIC) {
if (!strcmp(hdlr->path, req->path))
return (hdlr);
} else {
if (!regexec(&(hdlr->rctx), req->path,
HTTP_CAPTURE_GROUPS, req->cgroups, 0))
return (hdlr);
}
}
return (NULL);
}
#endif /* !KORE_NO_HTTP */
void *
kore_module_getsym(const char *symbol, struct kore_runtime **runtime)
{

View File

@ -22,6 +22,10 @@
#include "kore.h"
#include "http.h"
#if defined(KORE_USE_ACME)
#include "acme.h"
#endif
struct msg_type {
u_int8_t id;
void (*cb)(struct kore_msg *, const void *);
@ -29,9 +33,8 @@ struct msg_type {
};
static struct msg_type *msg_type_lookup(u_int8_t);
static int msg_recv_packet(struct netbuf *);
static int msg_recv_data(struct netbuf *);
static void msg_disconnected_parent(struct connection *);
static int msg_recv_packet(struct netbuf *);
static void msg_disconnected_worker(struct connection *);
static void msg_type_shutdown(struct kore_msg *, const void *);
@ -56,18 +59,8 @@ kore_msg_parent_init(void)
struct kore_worker *kw;
for (idx = 0; idx < worker_count; idx++) {
if (keymgr_active == 0) {
if (idx == KORE_WORKER_KEYMGR_IDX ||
idx == KORE_WORKER_ACME_IDX)
continue;
}
#if !defined(KORE_USE_ACME)
if (idx == KORE_WORKER_ACME_IDX)
continue;
#endif
kw = kore_worker_data(idx);
if (kw->ps != NULL)
kore_msg_parent_add(kw);
}
@ -119,7 +112,6 @@ kore_msg_worker_init(void)
worker->msg[1]->write = net_write;
worker->msg[1]->proto = CONN_PROTO_MSG;
worker->msg[1]->state = CONN_STATE_ESTABLISHED;
worker->msg[1]->disconnect = msg_disconnected_parent;
worker->msg[1]->handle = kore_connection_handle;
worker->msg[1]->evt.flags = KORE_EVENT_WRITE;
@ -147,7 +139,7 @@ kore_msg_register(u_int8_t id, void (*cb)(struct kore_msg *, const void *))
{
struct msg_type *type;
if ((type = msg_type_lookup(id)) != NULL)
if (msg_type_lookup(id) != NULL)
return (KORE_RESULT_ERROR);
type = kore_malloc(sizeof(*type));
@ -251,16 +243,6 @@ msg_recv_data(struct netbuf *nb)
return (KORE_RESULT_OK);
}
static void
msg_disconnected_parent(struct connection *c)
{
if (!kore_quiet)
kore_log(LOG_ERR, "parent gone, shutting down");
if (kill(worker->pid, SIGQUIT) == -1)
kore_log(LOG_ERR, "failed to send SIGQUIT: %s", errno_s);
}
static void
msg_disconnected_worker(struct connection *c)
{
@ -275,7 +257,7 @@ msg_type_shutdown(struct kore_msg *msg, const void *data)
"shutdown requested by worker %u, going down", msg->src);
}
(void)raise(SIGQUIT);
kore_quit = 1;
}
#if !defined(KORE_NO_HTTP)

View File

@ -292,6 +292,9 @@ net_recv_flush(struct connection *c)
if (c->rnb->buf == NULL)
return (KORE_RESULT_OK);
if ((c->rnb->b_len - c->rnb->s_off) == 0)
return (KORE_RESULT_OK);
if (!c->read(c, &r))
return (KORE_RESULT_ERROR);
if (!(c->evt.flags & KORE_EVENT_READ))

View File

@ -772,6 +772,10 @@ pgsql_read_result(struct kore_pgsql *pgsql)
}
switch (PQresultStatus(pgsql->result)) {
#if PG_VERSION_NUM >= 140000
case PGRES_PIPELINE_SYNC:
case PGRES_PIPELINE_ABORTED:
#endif
case PGRES_COPY_OUT:
case PGRES_COPY_IN:
case PGRES_NONFATAL_ERROR:

View File

@ -47,6 +47,8 @@ kore_pool_init(struct kore_pool *pool, const char *name,
if ((pool->name = strdup(name)) == NULL)
fatal("kore_pool_init: strdup %s", errno_s);
len = (len + (8 - 1)) & ~(8 - 1);
pool->lock = 0;
pool->elms = 0;
pool->inuse = 0;

File diff suppressed because it is too large Load Diff

138
src/route.c Normal file
View File

@ -0,0 +1,138 @@
/*
* Copyright (c) 2021 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/types.h>
#include <sys/stat.h>
#include <dlfcn.h>
#include "kore.h"
#include "http.h"
struct kore_route *
kore_route_create(struct kore_domain *dom, const char *path, int type)
{
struct kore_route *rt;
rt = kore_calloc(1, sizeof(*rt));
rt->dom = dom;
rt->type = type;
rt->path = kore_strdup(path);
rt->methods = HTTP_METHOD_ALL;
TAILQ_INIT(&rt->params);
if (rt->type == HANDLER_TYPE_DYNAMIC) {
if (regcomp(&rt->rctx, rt->path, REG_EXTENDED | REG_NOSUB)) {
kore_route_free(rt);
return (NULL);
}
}
TAILQ_INSERT_TAIL(&dom->routes, rt, list);
return (rt);
}
void
kore_route_free(struct kore_route *rt)
{
struct kore_route_params *param;
if (rt == NULL)
return;
kore_free(rt->func);
kore_free(rt->path);
if (rt->type == HANDLER_TYPE_DYNAMIC)
regfree(&rt->rctx);
/* Drop all validators associated with this handler */
while ((param = TAILQ_FIRST(&rt->params)) != NULL) {
TAILQ_REMOVE(&rt->params, param, list);
kore_free(param->name);
kore_free(param);
}
kore_free(rt);
}
void
kore_route_callback(struct kore_route *rt, const char *func)
{
if ((rt->rcall = kore_runtime_getcall(func)) == NULL)
fatal("callback '%s' for '%s' not found", func, rt->path);
kore_free(rt->func);
rt->func = kore_strdup(func);
}
int
kore_route_lookup(struct http_request *req, struct kore_domain *dom,
int method, struct kore_route **out)
{
struct kore_route *rt;
int exists;
exists = 0;
*out = NULL;
TAILQ_FOREACH(rt, &dom->routes, list) {
if (rt->type == HANDLER_TYPE_STATIC) {
if (!strcmp(rt->path, req->path)) {
if (rt->methods & method) {
*out = rt;
return (1);
}
exists++;
}
} else {
if (!regexec(&rt->rctx, req->path,
HTTP_CAPTURE_GROUPS, req->cgroups, 0)) {
if (rt->methods & method) {
*out = rt;
return (1);
}
exists++;
}
}
}
return (exists);
}
void
kore_route_reload(void)
{
struct kore_route *rt;
struct kore_server *srv;
struct kore_domain *dom;
LIST_FOREACH(srv, &kore_servers, list) {
TAILQ_FOREACH(dom, &srv->domains, list) {
TAILQ_FOREACH(rt, &dom->routes, list) {
kore_free(rt->rcall);
rt->rcall = kore_runtime_getcall(rt->func);
if (rt->rcall == NULL) {
fatal("no function '%s' for route '%s'",
rt->func, rt->path);
}
rt->errors = 0;
}
}
}
}

View File

@ -29,10 +29,14 @@
static void native_runtime_execute(void *);
static int native_runtime_onload(void *, int);
static void native_runtime_signal(void *, int);
static void native_runtime_connect(void *, struct connection *);
static void native_runtime_configure(void *, int, char **);
#if !defined(KORE_NO_HTTP)
static int native_runtime_http_request(void *, struct http_request *);
static void native_runtime_http_request_free(void *, struct http_request *);
static void native_runtime_http_body_chunk(void *, struct http_request *,
const void *, size_t);
static int native_runtime_validator(void *, struct http_request *,
const void *);
@ -44,12 +48,15 @@ struct kore_runtime kore_native_runtime = {
KORE_RUNTIME_NATIVE,
#if !defined(KORE_NO_HTTP)
.http_request = native_runtime_http_request,
.http_request_free = native_runtime_http_request_free,
.http_body_chunk = native_runtime_http_body_chunk,
.validator = native_runtime_validator,
.wsconnect = native_runtime_connect,
.wsmessage = native_runtime_wsmessage,
.wsdisconnect = native_runtime_connect,
#endif
.onload = native_runtime_onload,
.signal = native_runtime_signal,
.connect = native_runtime_connect,
.execute = native_runtime_execute,
.configure = native_runtime_configure
@ -97,6 +104,12 @@ kore_runtime_connect(struct kore_runtime_call *rcall, struct connection *c)
rcall->runtime->connect(rcall->addr, c);
}
void
kore_runtime_signal(struct kore_runtime_call *rcall, int sig)
{
rcall->runtime->signal(rcall->addr, sig);
}
#if !defined(KORE_NO_HTTP)
int
kore_runtime_http_request(struct kore_runtime_call *rcall,
@ -105,6 +118,20 @@ kore_runtime_http_request(struct kore_runtime_call *rcall,
return (rcall->runtime->http_request(rcall->addr, req));
}
void
kore_runtime_http_request_free(struct kore_runtime_call *rcall,
struct http_request *req)
{
rcall->runtime->http_request_free(rcall->addr, req);
}
void
kore_runtime_http_body_chunk(struct kore_runtime_call *rcall,
struct http_request *req, const void *data, size_t len)
{
rcall->runtime->http_body_chunk(rcall->addr, req, data, len);
}
int
kore_runtime_validator(struct kore_runtime_call *rcall,
struct http_request *req, const void *data)
@ -168,6 +195,15 @@ native_runtime_onload(void *addr, int action)
return (cb(action));
}
static void
native_runtime_signal(void *addr, int sig)
{
void (*cb)(int);
*(void **)&(cb) = addr;
cb(sig);
}
#if !defined(KORE_NO_HTTP)
static int
native_runtime_http_request(void *addr, struct http_request *req)
@ -178,6 +214,26 @@ native_runtime_http_request(void *addr, struct http_request *req)
return (cb(req));
}
static void
native_runtime_http_request_free(void *addr, struct http_request *req)
{
int (*cb)(struct http_request *);
*(void **)&(cb) = addr;
cb(req);
}
static void
native_runtime_http_body_chunk(void *addr, struct http_request *req,
const void *data, size_t len)
{
void (*cb)(struct http_request *, const void *, size_t);
*(void **)&(cb) = addr;
cb(req, data, len);
}
static int
native_runtime_validator(void *addr, struct http_request *req, const void *data)
{

View File

@ -90,6 +90,9 @@ static struct sock_filter filter_kore[] = {
#if defined(SYS_readlink)
KORE_SYSCALL_ALLOW(readlink),
#endif
#if defined(SYS_readlinkat)
KORE_SYSCALL_ALLOW(readlinkat),
#endif
/* Process related. */
KORE_SYSCALL_ALLOW(exit),

View File

@ -54,6 +54,9 @@ static int utils_base64_encode(const void *, size_t, char **,
const char *, int);
static int utils_base64_decode(const char *, u_int8_t **,
size_t *, const char *, int);
static int utils_x509name_tobuf(void *, int, int, const char *,
const void *, size_t, int);
static char b64_table[] = \
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@ -79,46 +82,6 @@ kore_debug_internal(char *file, int line, const char *fmt, ...)
}
#endif
void
kore_log_init(void)
{
#if defined(KORE_SINGLE_BINARY)
extern const char *__progname;
const char *name = kore_strdup(__progname);
#else
const char *name = "kore";
#endif
if (!kore_foreground)
openlog(name, LOG_NDELAY | LOG_PID, LOG_DAEMON);
}
void
kore_log(int prio, const char *fmt, ...)
{
va_list args;
const char *name;
char buf[2048];
va_start(args, fmt);
(void)vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
if (worker != NULL) {
name = kore_worker_name(worker->id);
if (kore_foreground)
printf("%s: %s\n", name, buf);
else
syslog(prio, "%s: %s", name, buf);
} else {
if (kore_foreground)
printf("[parent]: %s\n", buf);
else
syslog(prio, "[parent]: %s", buf);
}
}
size_t
kore_strlcpy(char *dst, const char *src, const size_t len)
{
@ -585,35 +548,72 @@ kore_worker_name(int id)
return (buf);
}
int
kore_x509_issuer_name(struct connection *c, char **out, int flags)
{
struct kore_buf buf;
X509_NAME *name;
if ((name = X509_get_issuer_name(c->cert)) == NULL)
return (KORE_RESULT_ERROR);
kore_buf_init(&buf, 1024);
if (!kore_x509name_foreach(name, flags, &buf, utils_x509name_tobuf)) {
kore_buf_cleanup(&buf);
return (KORE_RESULT_ERROR);
}
*out = kore_buf_stringify(&buf, NULL);
buf.offset = 0;
buf.data = NULL;
return (KORE_RESULT_OK);
}
int
kore_x509_subject_name(struct connection *c, char **out, int flags)
{
struct kore_buf buf;
X509_NAME *name;
if ((name = X509_get_subject_name(c->cert)) == NULL)
return (KORE_RESULT_ERROR);
kore_buf_init(&buf, 1024);
if (!kore_x509name_foreach(name, flags, &buf, utils_x509name_tobuf)) {
kore_buf_cleanup(&buf);
return (KORE_RESULT_ERROR);
}
*out = kore_buf_stringify(&buf, NULL);
buf.offset = 0;
buf.data = NULL;
return (KORE_RESULT_OK);
}
int
kore_x509name_foreach(X509_NAME *name, int flags, void *udata,
int (*cb)(void *, int, int, const char *, const void *, size_t, int))
{
u_int8_t *data;
ASN1_STRING *astr;
X509_NAME *name;
X509_NAME_ENTRY *entry;
const char *field;
int ret, idx, namelen, nid, len;
int islast, ret, idx, namelen, nid, len;
data = NULL;
ret = KORE_RESULT_ERROR;
kore_buf_init(&buf, 1024);
if (c->cert == NULL)
goto cleanup;
if ((name = X509_get_subject_name(c->cert)) == NULL)
goto cleanup;
namelen = X509_NAME_entry_count(name);
if (namelen == 0)
if ((namelen = X509_NAME_entry_count(name)) == 0)
goto cleanup;
for (idx = 0; idx < namelen; idx++) {
entry = X509_NAME_get_entry(name, idx);
if (entry == NULL)
if ((entry = X509_NAME_get_entry(name, idx)) == NULL)
goto cleanup;
nid = OBJ_obj2nid(X509_NAME_ENTRY_get_object(entry));
@ -627,33 +627,24 @@ kore_x509_subject_name(struct connection *c, char **out, int flags)
if ((len = ASN1_STRING_to_UTF8(&data, astr)) < 0)
goto cleanup;
if (flags & KORE_X509_COMMON_NAME_ONLY) {
if (nid == NID_commonName) {
kore_buf_append(&buf, data, len);
break;
}
} else {
kore_buf_appendf(&buf, "%s=", field);
kore_buf_append(&buf, data, len);
if (idx != (namelen - 1))
kore_buf_appendf(&buf, " ");
}
islast = 0;
else
islast = 1;
if (!cb(udata, islast, nid, field, data, len, flags))
goto cleanup;
OPENSSL_free(data);
data = NULL;
}
ret = KORE_RESULT_OK;
*out = kore_buf_stringify(&buf, NULL);
buf.offset = 0;
buf.data = NULL;
cleanup:
if (data != NULL)
OPENSSL_free(data);
kore_buf_cleanup(&buf);
return (ret);
}
@ -689,17 +680,31 @@ static void
fatal_log(const char *fmt, va_list args)
{
char buf[2048];
extern const char *kore_progname;
(void)vsnprintf(buf, sizeof(buf), fmt, args);
if (!kore_foreground)
kore_log(LOG_ERR, "%s", buf);
kore_log(LOG_ERR, "FATAL: %s", buf);
if (worker != NULL && worker->id == KORE_WORKER_KEYMGR)
kore_keymgr_cleanup(1);
}
printf("%s: %s\n", kore_progname, buf);
static int
utils_x509name_tobuf(void *udata, int islast, int nid, const char *field,
const void *data, size_t len, int flags)
{
struct kore_buf *buf = udata;
if (flags & KORE_X509_COMMON_NAME_ONLY) {
if (nid == NID_commonName)
kore_buf_append(buf, data, len);
} else {
kore_buf_appendf(buf, "%s=", field);
kore_buf_append(buf, data, len);
if (!islast)
kore_buf_appendf(buf, " ");
}
return (KORE_RESULT_OK);
}
static int

View File

@ -16,6 +16,7 @@
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <sys/time.h>
@ -28,6 +29,7 @@
#include <grp.h>
#include <pwd.h>
#include <signal.h>
#include <unistd.h>
#include "kore.h"
@ -77,6 +79,11 @@ struct wlock {
static int worker_trylock(void);
static void worker_unlock(void);
static void worker_reaper(pid_t, int);
static void worker_runtime_teardown(void);
static void worker_runtime_configure(void);
static void worker_domain_check(struct kore_domain *);
static struct kore_runtime_call *worker_runtime_signal(void);
static inline int worker_acceptlock_obtain(void);
static inline void worker_acceptlock_release(void);
@ -99,7 +106,7 @@ u_int32_t worker_max_connections = 512;
u_int32_t worker_active_connections = 0;
int worker_policy = KORE_WORKER_POLICY_RESTART;
void
int
kore_worker_init(void)
{
size_t len;
@ -143,42 +150,59 @@ kore_worker_init(void)
kw->lb.offset = 0;
}
if (!kore_quiet)
kore_log(LOG_INFO, "starting worker processes");
/* Now start all the workers. */
id = 1;
cpu = 1;
for (idx = KORE_WORKER_BASE; idx < worker_count; idx++) {
if (cpu >= cpu_count)
cpu = 0;
kore_worker_spawn(idx, id++, cpu++);
if (!kore_worker_spawn(idx, id++, cpu++))
return (KORE_RESULT_ERROR);
}
if (keymgr_active) {
#if defined(KORE_USE_ACME)
/* The ACME process is only started if we need it. */
if (acme_provider) {
kore_worker_spawn(KORE_WORKER_ACME_IDX,
KORE_WORKER_ACME, 0);
if (acme_domains) {
if (!kore_worker_spawn(KORE_WORKER_ACME_IDX,
KORE_WORKER_ACME, 0))
return (KORE_RESULT_ERROR);
}
#endif
/* Now we can start the keymgr. */
kore_worker_spawn(KORE_WORKER_KEYMGR_IDX,
KORE_WORKER_KEYMGR, 0);
if (!kore_worker_spawn(KORE_WORKER_KEYMGR_IDX,
KORE_WORKER_KEYMGR, 0))
return (KORE_RESULT_ERROR);
}
if (!kore_quiet)
kore_log(LOG_INFO, "all worker processes started");
return (KORE_RESULT_OK);
}
void
int
kore_worker_spawn(u_int16_t idx, u_int16_t id, u_int16_t cpu)
{
int cnt;
struct kore_worker *kw;
#if defined(__linux__)
int status;
#endif
kw = WORKER(idx);
kw->id = id;
kw->cpu = cpu;
kw->has_lock = 0;
kw->active_hdlr = NULL;
kw->running = 1;
kw->ready = 0;
kw->has_lock = 0;
kw->active_route = NULL;
if (socketpair(AF_UNIX, SOCK_STREAM, 0, kw->pipe) == -1)
fatal("socketpair(): %s", errno_s);
@ -186,6 +210,20 @@ kore_worker_spawn(u_int16_t idx, u_int16_t id, u_int16_t cpu)
!kore_connection_nonblock(kw->pipe[1], 0))
fatal("could not set pipe fds to nonblocking: %s", errno_s);
switch (id) {
case KORE_WORKER_KEYMGR:
kw->ps = &keymgr_privsep;
break;
#if defined(KORE_USE_ACME)
case KORE_WORKER_ACME:
kw->ps = &acme_privsep;
break;
#endif
default:
kw->ps = &worker_privsep;
break;
}
kw->pid = fork();
if (kw->pid == -1)
fatal("could not spawn worker child: %s", errno_s);
@ -193,8 +231,34 @@ kore_worker_spawn(u_int16_t idx, u_int16_t id, u_int16_t cpu)
if (kw->pid == 0) {
kw->pid = getpid();
kore_worker_entry(kw);
/* NOTREACHED */
exit(1);
} else {
for (cnt = 0; cnt < 50; cnt++) {
if (kw->ready == 1)
break;
usleep(100000);
#if defined(__linux__)
/*
* If seccomp_tracing is enabled, make sure we
* handle the SIGSTOP from the child processes.
*/
if (kore_seccomp_tracing) {
if (waitpid(kw->pid, &status, WNOHANG) > 0)
kore_seccomp_trace(kw->pid, status);
}
#endif
}
if (kw->ready == 0) {
kore_log(LOG_NOTICE,
"worker %d failed to start, shutting down",
kw->id);
return (KORE_RESULT_ERROR);
}
}
return (KORE_RESULT_OK);
}
struct kore_worker *
@ -237,9 +301,13 @@ kore_worker_shutdown(void)
kw->pid = 0;
kw->running = 0;
kw->msg[0]->evt.flags |= KORE_EVENT_READ;
net_recv_flush(kw->msg[0]);
if (!kore_quiet) {
kore_log(LOG_NOTICE, "worker %s exited",
kore_worker_name(kw->id));
kore_log(LOG_NOTICE,
"worker %s exited (%d)",
kore_worker_name(kw->id), status);
}
}
}
@ -282,37 +350,43 @@ kore_worker_dispatch_signal(int sig)
}
void
kore_worker_privdrop(const char *runas, const char *root)
kore_worker_privsep(void)
{
rlim_t fd;
struct rlimit rl;
struct passwd *pw = NULL;
struct passwd *pw;
if (root == NULL)
fatalx("no root directory for kore_worker_privdrop");
if (worker == NULL)
fatalx("%s called with no worker", __func__);
pw = NULL;
/* Must happen before chroot. */
if (skip_runas == 0) {
if (runas == NULL)
fatalx("no runas user given and -r not specified");
pw = getpwnam(runas);
if (pw == NULL) {
if (worker->ps->skip_runas == 0) {
if (worker->ps->runas == NULL) {
fatalx("no runas user given for %s",
kore_worker_name(worker->id));
}
if ((pw = getpwnam(worker->ps->runas)) == NULL) {
fatalx("cannot getpwnam(\"%s\") for user: %s",
runas, errno_s);
worker->ps->runas, errno_s);
}
}
if (skip_chroot == 0) {
if (chroot(root) == -1) {
if (worker->ps->skip_chroot == 0) {
if (chroot(worker->ps->root) == -1) {
fatalx("cannot chroot(\"%s\"): %s",
root, errno_s);
worker->ps->root, errno_s);
}
if (chdir("/") == -1)
fatalx("cannot chdir(\"/\"): %s", errno_s);
} else {
if (chdir(root) == -1)
fatalx("cannot chdir(\"%s\"): %s", root, errno_s);
if (chdir(worker->ps->root) == -1) {
fatalx("cannot chdir(\"%s\"): %s",
worker->ps->root, errno_s);
}
}
if (getrlimit(RLIMIT_NOFILE, &rl) == -1) {
@ -332,7 +406,7 @@ kore_worker_privdrop(const char *runas, const char *root)
worker_rlimit_nofiles, errno_s);
}
if (skip_runas == 0) {
if (worker->ps->skip_runas == 0) {
if (setgroups(1, &pw->pw_gid) ||
#if defined(__MACH__) || defined(NetBSD)
setgid(pw->pw_gid) || setegid(pw->pw_gid) ||
@ -341,7 +415,7 @@ kore_worker_privdrop(const char *runas, const char *root)
setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
#endif
fatalx("cannot drop privileges");
fatalx("cannot drop privileges (%s)", errno_s);
}
kore_platform_sandbox();
@ -350,13 +424,16 @@ kore_worker_privdrop(const char *runas, const char *root)
void
kore_worker_entry(struct kore_worker *kw)
{
struct kore_runtime_call *rcall;
struct kore_runtime_call *sigcall;
u_int64_t last_seed;
int quit, had_lock;
int quit, had_lock, sig;
u_int64_t netwait, now, next_timeo;
worker = kw;
if (!kore_foreground)
closelog();
#if defined(__linux__)
kore_seccomp_traceme();
#endif
@ -367,7 +444,6 @@ kore_worker_entry(struct kore_worker *kw)
kore_platform_worker_setcpu(kw);
kore_pid = kw->pid;
kore_signal_setup();
if (kw->id == KORE_WORKER_KEYMGR) {
@ -391,7 +467,7 @@ kore_worker_entry(struct kore_worker *kw)
kore_task_init();
#endif
kore_worker_privdrop(kore_runas_user, kore_root_path);
kore_worker_privsep();
#if !defined(KORE_NO_HTTP)
http_init();
@ -432,21 +508,16 @@ kore_worker_entry(struct kore_worker *kw)
if (nlisteners == 0)
worker_no_lock = 1;
if (!kore_quiet) {
kore_log(LOG_NOTICE,
"worker %d started (cpu#%d, pid#%d)",
kw->id, kw->cpu, kw->pid);
}
rcall = kore_runtime_getcall("kore_worker_configure");
if (rcall != NULL) {
kore_runtime_execute(rcall);
kore_free(rcall);
}
worker_runtime_configure();
kore_module_onload();
kore_domain_callback(worker_domain_check);
kore_worker_started();
worker->restarted = 0;
sigcall = worker_runtime_signal();
for (;;) {
now = kore_time_ms();
@ -495,8 +566,9 @@ kore_worker_entry(struct kore_worker *kw)
}
}
if (sig_recv != 0) {
switch (sig_recv) {
sig = sig_recv;
if (sig != 0) {
switch (sig) {
case SIGHUP:
kore_module_reload(1);
break;
@ -514,6 +586,10 @@ kore_worker_entry(struct kore_worker *kw)
break;
}
if (sigcall != NULL)
kore_runtime_signal(sigcall, sig);
if (sig == sig_recv)
sig_recv = 0;
}
@ -539,13 +615,7 @@ kore_worker_entry(struct kore_worker *kw)
kore_connection_prune(KORE_CONNECTION_PRUNE_DISCONNECT);
}
rcall = kore_runtime_getcall("kore_worker_teardown");
if (rcall != NULL) {
kore_runtime_execute(rcall);
kore_free(rcall);
}
kore_msg_send(KORE_MSG_PARENT, KORE_MSG_SHUTDOWN, NULL, 0);
worker_runtime_teardown();
kore_server_cleanup();
kore_platform_event_cleanup();
@ -577,16 +647,12 @@ kore_worker_reap(void)
pid_t pid;
int status;
for (;;) {
pid = waitpid(WAIT_ANY, &status, WNOHANG);
if (pid == -1) {
if (errno == ECHILD)
if (errno == ECHILD || errno == EINTR)
return;
if (errno == EINTR)
continue;
kore_log(LOG_ERR,
"failed to wait for children: %s", errno_s);
kore_log(LOG_ERR, "%s: waitpid(): %s", __func__, errno_s);
return;
}
@ -594,7 +660,6 @@ kore_worker_reap(void)
return;
worker_reaper(pid, status);
}
}
void
@ -669,6 +734,97 @@ kore_worker_keymgr_response_verify(struct kore_msg *msg, const void *data,
return (KORE_RESULT_OK);
}
void
kore_worker_started(void)
{
const char *chroot;
if (worker->ps->skip_chroot)
chroot = "root";
else
chroot = "chroot";
if (!kore_quiet) {
kore_log(LOG_NOTICE,
"started (#%d %s=%s%s%s)",
getpid(), chroot, worker->ps->root,
worker->ps->skip_runas ? "" : " user=",
worker->ps->skip_runas ? "" : worker->ps->runas);
}
worker->ready = 1;
}
static void
worker_runtime_configure(void)
{
struct kore_runtime_call *rcall;
rcall = NULL;
#if defined(KORE_USE_PYTHON)
rcall = kore_runtime_getcall(KORE_PYTHON_WORKER_START_HOOK);
#endif
if (rcall == NULL)
rcall = kore_runtime_getcall("kore_worker_configure");
if (rcall != NULL) {
kore_runtime_execute(rcall);
kore_free(rcall);
}
}
static struct kore_runtime_call *
worker_runtime_signal(void)
{
struct kore_runtime_call *rcall;
rcall = NULL;
#if defined(KORE_USE_PYTHON)
rcall = kore_runtime_getcall(KORE_PYTHON_SIGNAL_HOOK);
#endif
if (rcall == NULL)
rcall = kore_runtime_getcall("kore_worker_signal");
return (rcall);
}
static void
worker_runtime_teardown(void)
{
struct kore_runtime_call *rcall;
rcall = NULL;
#if defined(KORE_USE_PYTHON)
rcall = kore_runtime_getcall(KORE_PYTHON_WORKER_STOP_HOOK);
#endif
if (rcall == NULL)
rcall = kore_runtime_getcall("kore_worker_teardown");
if (rcall != NULL) {
kore_runtime_execute(rcall);
kore_free(rcall);
}
}
static void
worker_domain_check(struct kore_domain *dom)
{
struct stat st;
if (dom->cafile != NULL) {
if (stat(dom->cafile, &st) == -1)
fatalx("'%s': %s", dom->cafile, errno_s);
if (access(dom->cafile, R_OK) == -1)
fatalx("'%s': not readable", dom->cafile, errno_s);
}
}
static void
worker_reaper(pid_t pid, int status)
{
@ -686,6 +842,9 @@ worker_reaper(pid_t pid, int status)
if (kw->pid != pid)
continue;
kw->msg[0]->evt.flags |= KORE_EVENT_READ;
net_recv_flush(kw->msg[0]);
if (!kore_quiet) {
kore_log(LOG_NOTICE,
"worker %s (%d) exited with status %d",
@ -701,8 +860,8 @@ worker_reaper(pid_t pid, int status)
func = "none";
#if !defined(KORE_NO_HTTP)
if (kw->active_hdlr != NULL)
func = kw->active_hdlr->func;
if (kw->active_route != NULL)
func = kw->active_route->func;
#endif
kore_log(LOG_NOTICE,
"worker %d (pid: %d) (hdlr: %s) gone",
@ -720,10 +879,7 @@ worker_reaper(pid_t pid, int status)
kore_log(LOG_CRIT,
"keymgr or acme process gone, stopping");
kw->pid = 0;
if (raise(SIGTERM) != 0) {
kore_log(LOG_WARNING,
"failed to raise SIGTERM signal");
}
kore_quit = 1;
break;
}
@ -732,12 +888,12 @@ worker_reaper(pid_t pid, int status)
worker_unlock();
#if !defined(KORE_NO_HTTP)
if (kw->active_hdlr != NULL) {
kw->active_hdlr->errors++;
if (kw->active_route != NULL) {
kw->active_route->errors++;
kore_log(LOG_NOTICE,
"hdlr %s has caused %d error(s)",
kw->active_hdlr->func,
kw->active_hdlr->errors);
kw->active_route->func,
kw->active_route->errors);
}
#endif
@ -745,21 +901,25 @@ worker_reaper(pid_t pid, int status)
kw->pid = 0;
kore_log(LOG_NOTICE,
"worker policy is 'terminate', stopping");
if (raise(SIGTERM) != 0) {
kore_log(LOG_WARNING,
"failed to raise SIGTERM signal");
}
kore_quit = 1;
break;
}
if (kore_quit == 0) {
kore_log(LOG_NOTICE, "restarting worker %d", kw->id);
kw->restarted = 1;
kore_msg_parent_remove(kw);
kore_worker_spawn(idx, kw->id, kw->cpu);
if (!kore_worker_spawn(idx, kw->id, kw->cpu)) {
kore_quit = 1;
kore_log(LOG_ERR, "failed to restart worker");
} else {
kore_msg_parent_add(kw);
}
break;
}
}
}
static inline void
@ -899,7 +1059,10 @@ worker_keymgr_response(struct kore_msg *msg, const void *data)
case KORE_ACME_CHALLENGE_CLEAR_CERT:
dom->acme_cert_len = 0;
dom->acme_challenge = 0;
kore_free(dom->acme_cert);
dom->acme_cert = NULL;
kore_log(LOG_NOTICE, "[%s] tls-alpn-01 challenge disabled",
dom->domain);
break;