kore

Kore is a web application platform for writing scalable, concurrent web based processes in C or Python.
Commits | Files | Refs | README | LICENSE | git clone https://git.kore.io/kore.git

config.c (49749B)



      1 /*
      2  * Copyright (c) 2013-2022 Joris Vink <joris@coders.se>
      3  *
      4  * Permission to use, copy, modify, and distribute this software for any
      5  * purpose with or without fee is hereby granted, provided that the above
      6  * copyright notice and this permission notice appear in all copies.
      7  *
      8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     15  */
     16 
     17 #include <sys/param.h>
     18 #include <sys/types.h>
     19 #include <sys/stat.h>
     20 
     21 #include <stdio.h>
     22 #include <string.h>
     23 #include <stdint.h>
     24 #include <ctype.h>
     25 #include <limits.h>
     26 #include <fcntl.h>
     27 #include <pwd.h>
     28 
     29 #include "kore.h"
     30 #include "http.h"
     31 
     32 #if defined(KORE_USE_PGSQL)
     33 #include "pgsql.h"
     34 #endif
     35 
     36 #if defined(KORE_USE_TASKS)
     37 #include "tasks.h"
     38 #endif
     39 
     40 #if defined(KORE_USE_PYTHON)
     41 #include "python_api.h"
     42 #endif
     43 
     44 #if defined(KORE_USE_CURL)
     45 #include "curl.h"
     46 #endif
     47 
     48 #if defined(KORE_USE_ACME)
     49 #include "acme.h"
     50 #endif
     51 
     52 #if defined(__linux__)
     53 #include "seccomp.h"
     54 #endif
     55 
     56 /* XXX - This is becoming a clusterfuck. Fix it. */
     57 
     58 static int	configure_load(char *);
     59 static char	*configure_resolve_var(char *);
     60 static void	configure_check_var(char **, const char *, const char *);
     61 
     62 #if defined(KORE_SINGLE_BINARY)
     63 static FILE		*config_file_write(void);
     64 extern u_int8_t		asset_builtin_kore_conf[];
     65 extern u_int32_t	asset_len_builtin_kore_conf;
     66 #elif defined(KORE_USE_PYTHON)
     67 static int		configure_file(char *);
     68 #endif
     69 
     70 #if defined(KORE_USE_ACME)
     71 static int		configure_acme(char *);
     72 static int		configure_acme_email(char *);
     73 static int		configure_acme_provider(char *);
     74 #endif
     75 
     76 static int		configure_tls(char *);
     77 static int		configure_server(char *);
     78 static int		configure_include(char *);
     79 static int		configure_bind(char *);
     80 static int		configure_bind_unix(char *);
     81 static int		configure_attach(char *);
     82 static int		configure_domain(char *);
     83 static int		configure_privsep(char *);
     84 static int		configure_logfile(char *);
     85 static int		configure_workers(char *);
     86 static int		configure_pidfile(char *);
     87 static int		configure_no_accept(char *);
     88 static int		configure_rlimit_nofiles(char *);
     89 static int		configure_max_connections(char *);
     90 static int		configure_accept_threshold(char *);
     91 static int		configure_death_policy(char *);
     92 static int		configure_set_affinity(char *);
     93 static int		configure_socket_backlog(char *);
     94 static int		configure_privsep_skip(char *);
     95 static int		configure_privsep_root(char *);
     96 static int		configure_privsep_runas(char *);
     97 static int		configure_deployment(char *);
     98 
     99 #if defined(KORE_USE_PLATFORM_PLEDGE)
    100 static int		configure_add_pledge(char *);
    101 #endif
    102 
    103 static int		configure_rand_file(char *);
    104 static int		configure_certfile(char *);
    105 static int		configure_certkey(char *);
    106 static int		configure_tls_version(char *);
    107 static int		configure_tls_cipher(char *);
    108 static int		configure_tls_dhparam(char *);
    109 static int		configure_client_verify(char *);
    110 static int		configure_client_verify_depth(char *);
    111 
    112 #if !defined(KORE_NO_HTTP)
    113 static int		configure_route(char *);
    114 static int		configure_route_methods(char *);
    115 static int		configure_route_handler(char *);
    116 static int		configure_route_on_free(char *);
    117 static int		configure_route_on_headers(char *);
    118 static int		configure_route_authenticate(char *);
    119 static int		configure_route_on_body_chunk(char *);
    120 static int		configure_filemap(char *);
    121 static int		configure_return(char *);
    122 static int		configure_redirect(char *);
    123 static int		configure_static_handler(char *);
    124 static int		configure_dynamic_handler(char *);
    125 static int		configure_accesslog(char *);
    126 static int		configure_http_header_max(char *);
    127 static int		configure_http_header_timeout(char *);
    128 static int		configure_http_body_max(char *);
    129 static int		configure_http_body_timeout(char *);
    130 static int		configure_filemap_ext(char *);
    131 static int		configure_filemap_index(char *);
    132 static int		configure_http_media_type(char *);
    133 static int		configure_http_hsts_enable(char *);
    134 static int		configure_http_keepalive_time(char *);
    135 static int		configure_http_request_ms(char *);
    136 static int		configure_http_request_limit(char *);
    137 static int		configure_http_body_disk_offload(char *);
    138 static int		configure_http_body_disk_path(char *);
    139 static int		configure_http_server_version(char *);
    140 static int		configure_http_pretty_error(char *);
    141 static int		configure_validator(char *);
    142 static int		configure_validate(char *);
    143 static int		configure_authentication(char *);
    144 static int		configure_authentication_uri(char *);
    145 static int		configure_authentication_type(char *);
    146 static int		configure_authentication_value(char *);
    147 static int		configure_authentication_validator(char *);
    148 static int		configure_websocket_maxframe(char *);
    149 static int		configure_websocket_timeout(char *);
    150 #endif
    151 
    152 #if defined(KORE_USE_PGSQL)
    153 static int		configure_pgsql_conn_max(char *);
    154 static int		configure_pgsql_queue_limit(char *);
    155 #endif
    156 
    157 #if defined(KORE_USE_TASKS)
    158 static int		configure_task_threads(char *);
    159 #endif
    160 
    161 #if defined(KORE_USE_PYTHON)
    162 static int		configure_python_path(char *);
    163 static int		configure_python_import(char *);
    164 #endif
    165 
    166 #if defined(KORE_USE_CURL)
    167 static int		configure_curl_timeout(char *);
    168 static int		configure_curl_recv_max(char *);
    169 #endif
    170 
    171 #if defined(__linux__)
    172 static int		configure_seccomp_tracing(char *);
    173 #endif
    174 
    175 static struct {
    176 	const char		*name;
    177 	int			(*configure)(char *);
    178 } config_directives[] = {
    179 	{ "tls",			configure_tls },
    180 #if defined(KORE_USE_ACME)
    181 	{ "acme",			configure_acme },
    182 #endif
    183 	{ "bind",			configure_bind },
    184 	{ "load",			configure_load },
    185 	{ "domain",			configure_domain },
    186 	{ "privsep",			configure_privsep },
    187 	{ "server",			configure_server },
    188 	{ "attach",			configure_attach },
    189 	{ "certkey",			configure_certkey },
    190 	{ "certfile",			configure_certfile },
    191 	{ "include",			configure_include },
    192 	{ "unix",			configure_bind_unix },
    193 	{ "skip",			configure_privsep_skip },
    194 	{ "root",			configure_privsep_root },
    195 	{ "runas",			configure_privsep_runas },
    196 	{ "client_verify",		configure_client_verify },
    197 	{ "client_verify_depth",	configure_client_verify_depth },
    198 #if defined(KORE_USE_PYTHON)
    199 	{ "python_path",		configure_python_path },
    200 	{ "python_import",		configure_python_import },
    201 #endif
    202 #if !defined(KORE_NO_HTTP)
    203 	{ "route",			configure_route },
    204 	{ "handler",			configure_route_handler },
    205 	{ "on_headers",			configure_route_on_headers },
    206 	{ "on_body_chunk",		configure_route_on_body_chunk },
    207 	{ "on_free",			configure_route_on_free },
    208 	{ "methods",			configure_route_methods },
    209 	{ "authenticate",		configure_route_authenticate },
    210 	{ "filemap",			configure_filemap },
    211 	{ "redirect",			configure_redirect },
    212 	{ "return",			configure_return },
    213 	{ "static",			configure_static_handler },
    214 	{ "dynamic",			configure_dynamic_handler },
    215 	{ "accesslog",			configure_accesslog },
    216 	{ "validator",			configure_validator },
    217 	{ "validate",			configure_validate },
    218 	{ "authentication",		configure_authentication },
    219 	{ "authentication_uri",		configure_authentication_uri },
    220 	{ "authentication_type",	configure_authentication_type },
    221 	{ "authentication_value",	configure_authentication_value },
    222 	{ "authentication_validator",	configure_authentication_validator },
    223 #endif
    224 	{ NULL,				NULL },
    225 };
    226 
    227 static struct {
    228 	const char		*name;
    229 	int			(*configure)(char *);
    230 } config_settings[] = {
    231 	{ "logfile",			configure_logfile },
    232 	{ "workers",			configure_workers },
    233 	{ "worker_max_connections",	configure_max_connections },
    234 	{ "worker_rlimit_nofiles",	configure_rlimit_nofiles },
    235 	{ "worker_accept_threshold",	configure_accept_threshold },
    236 	{ "worker_death_policy",	configure_death_policy },
    237 	{ "worker_set_affinity",	configure_set_affinity },
    238 	{ "pidfile",			configure_pidfile },
    239 	{ "worker_no_accept",		configure_no_accept },
    240 	{ "socket_backlog",		configure_socket_backlog },
    241 	{ "tls_version",		configure_tls_version },
    242 	{ "tls_cipher",			configure_tls_cipher },
    243 	{ "tls_dhparam",		configure_tls_dhparam },
    244 	{ "rand_file",			configure_rand_file },
    245 	{ "deployment",			configure_deployment },
    246 #if defined(KORE_USE_ACME)
    247 	{ "acme_email",			configure_acme_email },
    248 	{ "acme_provider",		configure_acme_provider },
    249 #endif
    250 #if defined(KORE_USE_PLATFORM_PLEDGE)
    251 	{ "pledge",			configure_add_pledge },
    252 #endif
    253 #if defined(__linux__)
    254 	{ "seccomp_tracing",		configure_seccomp_tracing },
    255 #endif
    256 #if !defined(KORE_NO_HTTP)
    257 	{ "filemap_ext",		configure_filemap_ext },
    258 	{ "filemap_index",		configure_filemap_index },
    259 	{ "http_media_type",		configure_http_media_type },
    260 	{ "http_header_max",		configure_http_header_max },
    261 	{ "http_header_timeout",	configure_http_header_timeout },
    262 	{ "http_body_max",		configure_http_body_max },
    263 	{ "http_body_timeout",		configure_http_body_timeout },
    264 	{ "http_hsts_enable",		configure_http_hsts_enable },
    265 	{ "http_keepalive_time",	configure_http_keepalive_time },
    266 	{ "http_request_ms",		configure_http_request_ms },
    267 	{ "http_request_limit",		configure_http_request_limit },
    268 	{ "http_body_disk_offload",	configure_http_body_disk_offload },
    269 	{ "http_body_disk_path",	configure_http_body_disk_path },
    270 	{ "http_server_version",	configure_http_server_version },
    271 	{ "http_pretty_error",		configure_http_pretty_error },
    272 	{ "websocket_maxframe",		configure_websocket_maxframe },
    273 	{ "websocket_timeout",		configure_websocket_timeout },
    274 #endif
    275 #if defined(KORE_USE_PGSQL)
    276 	{ "pgsql_conn_max",		configure_pgsql_conn_max },
    277 	{ "pgsql_queue_limit",		configure_pgsql_queue_limit },
    278 #endif
    279 #if defined(KORE_USE_TASKS)
    280 	{ "task_threads",		configure_task_threads },
    281 #endif
    282 #if defined(KORE_USE_CURL)
    283 	{ "curl_timeout",		configure_curl_timeout },
    284 	{ "curl_recv_max",		configure_curl_recv_max },
    285 #endif
    286 #if !defined(KORE_SINGLE_BINARY) && defined(KORE_USE_PYTHON)
    287 	{ "file",			configure_file },
    288 #endif
    289 	{ NULL,				NULL },
    290 };
    291 
    292 static int				finalized = 0;
    293 
    294 #if !defined(KORE_SINGLE_BINARY)
    295 char					*config_file = NULL;
    296 #endif
    297 
    298 #if !defined(KORE_NO_HTTP)
    299 static struct kore_auth			*current_auth = NULL;
    300 static struct kore_route		*current_route = NULL;
    301 #endif
    302 
    303 extern const char			*__progname;
    304 static struct kore_domain		*current_domain = NULL;
    305 static struct kore_server		*current_server = NULL;
    306 static struct kore_privsep		*current_privsep = NULL;
    307 
    308 void
    309 kore_parse_config(void)
    310 {
    311 	FILE		*fp;
    312 	struct passwd	*pwd;
    313 	char		path[PATH_MAX];
    314 
    315 	if (finalized)
    316 		return;
    317 
    318 	fp = NULL;
    319 
    320 #if !defined(KORE_SINGLE_BINARY)
    321 	if (config_file != NULL) {
    322 		if ((fp = fopen(config_file, "r")) == NULL) {
    323 			fatal("configuration given cannot be opened: %s",
    324 			    config_file);
    325 		}
    326 	}
    327 #else
    328 	fp = config_file_write();
    329 #endif
    330 
    331 	if (fp != NULL) {
    332 		kore_parse_config_file(fp);
    333 		(void)fclose(fp);
    334 	}
    335 
    336 	kore_tls_dh_check();
    337 
    338 	if (!kore_module_loaded())
    339 		fatal("no application module was loaded");
    340 
    341 	if (worker_privsep.root == NULL) {
    342 		if (getcwd(path, sizeof(path)) == NULL)
    343 			fatal("getcwd: %s", errno_s);
    344 		worker_privsep.root = kore_strdup(path);
    345 
    346 		if (!kore_quiet)
    347 			kore_log(LOG_NOTICE, "privsep: no root path set");
    348 	}
    349 
    350 	if (worker_privsep.runas == NULL) {
    351 		if ((pwd = getpwuid(getuid())) == NULL)
    352 			fatal("getpwuid: %s", errno_s);
    353 
    354 		worker_privsep.runas = kore_strdup(pwd->pw_name);
    355 		if (!kore_quiet)
    356 			kore_log(LOG_NOTICE, "privsep: no runas user set");
    357 
    358 		endpwent();
    359 	}
    360 
    361 	configure_check_var(&keymgr_privsep.runas, worker_privsep.runas,
    362 		"privsep: no keymgr runas set");
    363 #if defined(KORE_USE_ACME)
    364 	configure_check_var(&acme_privsep.runas, worker_privsep.runas,
    365 		"privsep: no acme runas set");
    366 #endif
    367 
    368 	configure_check_var(&keymgr_privsep.root, worker_privsep.root,
    369 		"privsep: no keymgr root set");
    370 #if defined(KORE_USE_ACME)
    371 	configure_check_var(&acme_privsep.root, worker_privsep.root,
    372 		"privsep: no acme root set");
    373 #endif
    374 
    375 	if (skip_chroot) {
    376 		worker_privsep.skip_chroot = 1;
    377 		keymgr_privsep.skip_chroot = 1;
    378 #if defined(KORE_USE_ACME)
    379 		acme_privsep.skip_chroot = 1;
    380 #endif
    381 	}
    382 
    383 	if (skip_runas) {
    384 		worker_privsep.skip_runas = 1;
    385 		keymgr_privsep.skip_runas = 1;
    386 #if defined(KORE_USE_ACME)
    387 		acme_privsep.skip_runas = 1;
    388 #endif
    389 	}
    390 
    391 	if (skip_runas && !kore_quiet)
    392 		kore_log(LOG_NOTICE, "privsep: skipping all runas options");
    393 
    394 	if (skip_chroot && !kore_quiet)
    395 		kore_log(LOG_NOTICE, "privsep: skipping all chroot options");
    396 
    397 	finalized = 1;
    398 }
    399 
    400 void
    401 kore_parse_config_file(FILE *fp)
    402 {
    403 	int		i, lineno;
    404 	char		buf[BUFSIZ], *p, *t, *v;
    405 
    406 	lineno = 1;
    407 	while ((p = kore_read_line(fp, buf, sizeof(buf))) != NULL) {
    408 		if (strlen(p) == 0) {
    409 			lineno++;
    410 			continue;
    411 		}
    412 
    413 		if (!strcmp(p, "}") && current_privsep != NULL) {
    414 			lineno++;
    415 			current_privsep = NULL;
    416 			continue;
    417 		}
    418 
    419 		if (!strcmp(p, "}") && current_server != NULL) {
    420 			lineno++;
    421 			kore_server_finalize(current_server);
    422 			current_server = NULL;
    423 			continue;
    424 		}
    425 
    426 #if !defined(KORE_NO_HTTP)
    427 		if (!strcmp(p, "}") && current_route != NULL) {
    428 			lineno++;
    429 			current_route = NULL;
    430 			continue;
    431 		}
    432 
    433 		if (!strcmp(p, "}") && current_auth != NULL) {
    434 			if (current_auth->validator == NULL) {
    435 				fatal("no authentication validator for %s",
    436 				    current_auth->name);
    437 			}
    438 
    439 			lineno++;
    440 			current_auth = NULL;
    441 			continue;
    442 		}
    443 #endif
    444 
    445 		if (!strcmp(p, "}") && current_domain != NULL) {
    446 			if (current_domain->server == NULL) {
    447 				fatal("domain '%s' not attached to server",
    448 				    current_domain->domain);
    449 			}
    450 
    451 			if (current_domain->server->tls == 1) {
    452 #if defined(KORE_USE_ACME)
    453 				if (current_domain->acme) {
    454 					lineno++;
    455 					current_domain = NULL;
    456 					continue;
    457 				}
    458 #endif
    459 				if (current_domain->certfile == NULL ||
    460 				    current_domain->certkey == NULL) {
    461 					fatal("incomplete TLS setup for '%s'",
    462 					    current_domain->domain);
    463 				}
    464 			}
    465 
    466 			current_domain = NULL;
    467 		}
    468 
    469 		if (!strcmp(p, "}")) {
    470 			lineno++;
    471 			continue;
    472 		}
    473 
    474 		if ((t = strchr(p, ' ')) == NULL) {
    475 			kore_log(LOG_NOTICE,
    476 			    "ignoring \"%s\" on line %d", p, lineno++);
    477 			continue;
    478 		}
    479 
    480 		*(t)++ = '\0';
    481 
    482 		p = kore_text_trim(p, strlen(p));
    483 		t = kore_text_trim(t, strlen(t));
    484 
    485 		if (strlen(p) == 0 || strlen(t) == 0) {
    486 			kore_log(LOG_NOTICE,
    487 			    "ignoring \"%s\" on line %d", p, lineno++);
    488 			continue;
    489 		}
    490 
    491 		for (i = 0; config_directives[i].name != NULL; i++) {
    492 			if (!strcmp(config_directives[i].name, p)) {
    493 				if ((v  = configure_resolve_var(t)) == NULL)
    494 					fatal("variable %s does not exist", t);
    495 				if (config_directives[i].configure(v))
    496 					break;
    497 				fatal("configuration error on line %d", lineno);
    498 				/* NOTREACHED */
    499 			}
    500 		}
    501 
    502 		if (config_directives[i].name != NULL) {
    503 			lineno++;
    504 			continue;
    505 		}
    506 
    507 		for (i = 0; config_settings[i].name != NULL; i++) {
    508 			if (!strcmp(config_settings[i].name, p)) {
    509 				if ((v  = configure_resolve_var(t)) == NULL)
    510 					fatal("variable %s does not exist", t);
    511 				if (config_settings[i].configure(v))
    512 					break;
    513 				fatal("configuration error on line %d", lineno);
    514 				/* NOTREACHED */
    515 			}
    516 		}
    517 
    518 		if (config_settings[i].name == NULL) {
    519 			kore_log(LOG_NOTICE,
    520 			    "ignoring \"%s\" on line %d", p, lineno);
    521 		}
    522 
    523 		lineno++;
    524 	}
    525 }
    526 
    527 int
    528 kore_configure_setting(const char *name, char *value)
    529 {
    530 	int	i;
    531 
    532 	if (finalized)
    533 		return (KORE_RESULT_ERROR);
    534 
    535 	for (i = 0; config_settings[i].name != NULL; i++) {
    536 		if (!strcmp(config_settings[i].name, name)) {
    537 			if (config_settings[i].configure(value))
    538 				return (KORE_RESULT_OK);
    539 			fatal("bad value '%s' for '%s'", value, name);
    540 		}
    541 	}
    542 
    543 	kore_log(LOG_NOTICE, "ignoring unknown kore.config.%s setting", name);
    544 	return (KORE_RESULT_OK);
    545 }
    546 
    547 static void
    548 configure_check_var(char **var, const char *other, const char *logmsg)
    549 {
    550 	if (*var == NULL) {
    551 		if (!kore_quiet)
    552 			kore_log(LOG_NOTICE, "%s", logmsg);
    553 		*var = kore_strdup(other);
    554 	}
    555 }
    556 
    557 static char *
    558 configure_resolve_var(char *var)
    559 {
    560 	char	*v;
    561 
    562 	if (var[0] == '$') {
    563 		if ((v = getenv(&var[1])) == NULL)
    564 			return (NULL);
    565 	} else {
    566 		v = var;
    567 	}
    568 
    569 	return (v);
    570 }
    571 
    572 static int
    573 configure_include(char *path)
    574 {
    575 	FILE		*fp;
    576 
    577 	if ((fp = fopen(path, "r")) == NULL)
    578 		fatal("failed to open include '%s'", path);
    579 
    580 	kore_parse_config_file(fp);
    581 	(void)fclose(fp);
    582 
    583 	return (KORE_RESULT_OK);
    584 }
    585 
    586 static int
    587 configure_server(char *options)
    588 {
    589 	struct kore_server	*srv;
    590 	char			*argv[3];
    591 
    592 	if (current_server != NULL) {
    593 		kore_log(LOG_ERR, "nested server contexts are not allowed");
    594 		return (KORE_RESULT_ERROR);
    595 	}
    596 
    597 	kore_split_string(options, " ", argv, 3);
    598 
    599 	if (argv[0] == NULL || argv[1] == NULL) {
    600 		kore_log(LOG_ERR, "server context invalid");
    601 		return (KORE_RESULT_ERROR);
    602 	}
    603 
    604 	if (strcmp(argv[1], "{")) {
    605 		kore_log(LOG_ERR, "server context not opened correctly");
    606 		return (KORE_RESULT_ERROR);
    607 	}
    608 
    609 	if ((srv = kore_server_lookup(argv[0])) != NULL) {
    610 		kore_log(LOG_ERR, "server with name '%s' exists", srv->name);
    611 		return (KORE_RESULT_ERROR);
    612 	}
    613 
    614 	current_server = kore_server_create(argv[0]);
    615 
    616 	return (KORE_RESULT_OK);
    617 }
    618 
    619 static int
    620 configure_tls(char *yesno)
    621 {
    622 	if (!kore_tls_supported()) {
    623 		current_server->tls = 0;
    624 
    625 		if (!strcmp(yesno, "yes")) {
    626 			kore_log(LOG_ERR, "TLS not supported in this build");
    627 			return (KORE_RESULT_ERROR);
    628 		}
    629 
    630 		return (KORE_RESULT_OK);
    631 	}
    632 
    633 	if (current_server == NULL) {
    634 		kore_log(LOG_ERR, "tls keyword not inside a server context");
    635 		return (KORE_RESULT_ERROR);
    636 	}
    637 
    638 	if (!strcmp(yesno, "no")) {
    639 		current_server->tls = 0;
    640 	} else if (!strcmp(yesno, "yes")) {
    641 		current_server->tls = 1;
    642 	} else {
    643 		kore_log(LOG_ERR, "invalid '%s' for yes|no tls option", yesno);
    644 		return (KORE_RESULT_ERROR);
    645 	}
    646 
    647 	return (KORE_RESULT_OK);
    648 }
    649 
    650 #if defined(KORE_USE_ACME)
    651 static int
    652 configure_acme(char *yesno)
    653 {
    654 	if (current_domain == NULL) {
    655 		kore_log(LOG_ERR, "acme keyword not inside a domain context");
    656 		return (KORE_RESULT_ERROR);
    657 	}
    658 
    659 	if (strchr(current_domain->domain, '*')) {
    660 		kore_log(LOG_ERR,
    661 		    "wildcards not supported due to lack of dns-01");
    662 		return (KORE_RESULT_ERROR);
    663 	}
    664 
    665 	if (!strcmp(yesno, "no")) {
    666 		current_domain->acme = 0;
    667 	} else if (!strcmp(yesno, "yes")) {
    668 		current_domain->acme = 1;
    669 
    670 		/* Override keyfile and certfile locations. */
    671 		kore_free(current_domain->certkey);
    672 		kore_free(current_domain->certfile);
    673 
    674 		kore_acme_get_paths(current_domain->domain,
    675 		    &current_domain->certkey, &current_domain->certfile);
    676 		acme_domains++;
    677 	} else {
    678 		kore_log(LOG_ERR, "invalid '%s' for yes|no acme option", yesno);
    679 		return (KORE_RESULT_ERROR);
    680 	}
    681 
    682 	return (KORE_RESULT_OK);
    683 }
    684 
    685 static int
    686 configure_acme_email(char *email)
    687 {
    688 	kore_free(acme_email);
    689 	acme_email = kore_strdup(email);
    690 
    691 	return (KORE_RESULT_OK);
    692 }
    693 
    694 static int
    695 configure_acme_provider(char *provider)
    696 {
    697 	kore_free(acme_provider);
    698 	acme_provider = kore_strdup(provider);
    699 
    700 	return (KORE_RESULT_OK);
    701 }
    702 
    703 #endif
    704 
    705 static int
    706 configure_bind(char *options)
    707 {
    708 	char		*argv[4];
    709 
    710 	if (current_server == NULL) {
    711 		kore_log(LOG_ERR, "bind keyword not inside a server context");
    712 		return (KORE_RESULT_ERROR);
    713 	}
    714 
    715 	kore_split_string(options, " ", argv, 4);
    716 	if (argv[0] == NULL || argv[1] == NULL)
    717 		return (KORE_RESULT_ERROR);
    718 
    719 	return (kore_server_bind(current_server, argv[0], argv[1], argv[2]));
    720 }
    721 
    722 static int
    723 configure_bind_unix(char *options)
    724 {
    725 	char		*argv[3];
    726 
    727 	if (current_server == NULL) {
    728 		kore_log(LOG_ERR,
    729 		    "bind_unix keyword not inside a server context");
    730 		return (KORE_RESULT_ERROR);
    731 	}
    732 
    733 	kore_split_string(options, " ", argv, 3);
    734 	if (argv[0] == NULL)
    735 		return (KORE_RESULT_ERROR);
    736 
    737 	return (kore_server_bind_unix(current_server, argv[0], argv[1]));
    738 }
    739 
    740 static int
    741 configure_load(char *options)
    742 {
    743 	char		*argv[3];
    744 
    745 	kore_split_string(options, " ", argv, 3);
    746 	if (argv[0] == NULL)
    747 		return (KORE_RESULT_ERROR);
    748 
    749 	kore_module_load(argv[0], argv[1], KORE_MODULE_NATIVE);
    750 	return (KORE_RESULT_OK);
    751 }
    752 
    753 #if defined(KORE_SINGLE_BINARY)
    754 static FILE *
    755 config_file_write(void)
    756 {
    757 	FILE		*fp;
    758 	ssize_t		ret;
    759 	int		fd, len;
    760 	char		fpath[MAXPATHLEN];
    761 
    762 	len = snprintf(fpath, sizeof(fpath), "%s/%s.XXXXXX", KORE_TMPDIR,
    763 	    __progname);
    764 	if (len == -1 || (size_t)len >= sizeof(fpath))
    765 		fatal("failed to create temporary path");
    766 
    767 	if ((fd = mkstemp(fpath)) == -1)
    768 		fatal("mkstemp(%s): %s", fpath, errno_s);
    769 
    770 	(void)unlink(fpath);
    771 
    772 	for (;;) {
    773 		ret = write(fd, asset_builtin_kore_conf,
    774 		    asset_len_builtin_kore_conf);
    775 		if (ret == -1) {
    776 			if (errno == EINTR)
    777 				continue;
    778 			fatal("failed to write temporary config: %s", errno_s);
    779 		}
    780 
    781 		if ((size_t)ret != asset_len_builtin_kore_conf)
    782 			fatal("failed to write temporary config");
    783 		break;
    784 	}
    785 
    786 	if ((fp = fdopen(fd, "w+")) == NULL)
    787 		fatal("fdopen(): %s", errno_s);
    788 
    789 	rewind(fp);
    790 
    791 	return (fp);
    792 }
    793 #elif defined(KORE_USE_PYTHON)
    794 static int
    795 configure_file(char *file)
    796 {
    797 	free(config_file);
    798 	if ((config_file = strdup(file)) == NULL)
    799 		fatal("strdup");
    800 
    801 	return (KORE_RESULT_OK);
    802 }
    803 #endif
    804 
    805 static int
    806 configure_tls_version(char *version)
    807 {
    808 	int	ver;
    809 
    810 	if (!strcmp(version, "1.3")) {
    811 		ver = KORE_TLS_VERSION_1_3;
    812 	} else if (!strcmp(version, "1.2")) {
    813 		ver = KORE_TLS_VERSION_1_2;
    814 	} else if (!strcmp(version, "both")) {
    815 		ver = KORE_TLS_VERSION_BOTH;
    816 	} else {
    817 		kore_log(LOG_ERR,
    818 		    "unknown value for tls_version: %s (use 1.3, 1.2, both)",
    819 		    version);
    820 		return (KORE_RESULT_ERROR);
    821 	}
    822 
    823 	kore_tls_version_set(ver);
    824 
    825 	return (KORE_RESULT_OK);
    826 }
    827 
    828 static int
    829 configure_tls_cipher(char *cipherlist)
    830 {
    831 	return (kore_tls_ciphersuite_set(cipherlist));
    832 }
    833 
    834 static int
    835 configure_tls_dhparam(char *path)
    836 {
    837 	return (kore_tls_dh_load(path));
    838 }
    839 
    840 static int
    841 configure_client_verify_depth(char *value)
    842 {
    843 	int	err, depth;
    844 
    845 	if (current_domain == NULL) {
    846 		kore_log(LOG_ERR,
    847 		    "client_verify_depth keyword not in domain context");
    848 		return (KORE_RESULT_ERROR);
    849 	}
    850 
    851 	depth = kore_strtonum(value, 10, 0, INT_MAX, &err);
    852 	if (err != KORE_RESULT_OK) {
    853 		kore_log(LOG_ERR, "bad client_verify_depth value: %s", value);
    854 		return (KORE_RESULT_ERROR);
    855 	}
    856 
    857 	current_domain->x509_verify_depth = depth;
    858 
    859 	return (KORE_RESULT_OK);
    860 }
    861 
    862 static int
    863 configure_client_verify(char *options)
    864 {
    865 	char		*argv[3];
    866 
    867 	if (current_domain == NULL) {
    868 		kore_log(LOG_ERR,
    869 		    "client_verify keyword not in domain context");
    870 		return (KORE_RESULT_ERROR);
    871 	}
    872 
    873 	kore_split_string(options, " ", argv, 3);
    874 	if (argv[0] == NULL) {
    875 		kore_log(LOG_ERR, "client_verify is missing a parameter");
    876 		return (KORE_RESULT_ERROR);
    877 	}
    878 
    879 	if (current_domain->cafile != NULL) {
    880 		kore_log(LOG_ERR, "client_verify already set for '%s'",
    881 		    current_domain->domain);
    882 		return (KORE_RESULT_ERROR);
    883 	}
    884 
    885 	current_domain->cafile = kore_strdup(argv[0]);
    886 	if (argv[1] != NULL)
    887 		current_domain->crlfile = kore_strdup(argv[1]);
    888 
    889 	return (KORE_RESULT_OK);
    890 }
    891 
    892 static int
    893 configure_rand_file(char *path)
    894 {
    895 	if (kore_rand_file != NULL)
    896 		kore_free(kore_rand_file);
    897 
    898 	kore_rand_file = kore_strdup(path);
    899 
    900 	return (KORE_RESULT_OK);
    901 }
    902 
    903 static int
    904 configure_certfile(char *path)
    905 {
    906 	if (current_domain == NULL) {
    907 		kore_log(LOG_ERR,
    908 		    "certfile keyword not specified in domain context");
    909 		return (KORE_RESULT_ERROR);
    910 	}
    911 
    912 	kore_free(current_domain->certfile);
    913 	current_domain->certfile = kore_strdup(path);
    914 	return (KORE_RESULT_OK);
    915 }
    916 
    917 static int
    918 configure_certkey(char *path)
    919 {
    920 	if (current_domain == NULL) {
    921 		kore_log(LOG_ERR,
    922 		    "certkey keyword not specified in domain context");
    923 		return (KORE_RESULT_ERROR);
    924 	}
    925 
    926 	kore_free(current_domain->certkey);
    927 	current_domain->certkey = kore_strdup(path);
    928 	return (KORE_RESULT_OK);
    929 }
    930 
    931 static int
    932 configure_privsep(char *options)
    933 {
    934 	char		*argv[3];
    935 
    936 	if (current_privsep != NULL) {
    937 		kore_log(LOG_ERR, "nested privsep contexts are not allowed");
    938 		return (KORE_RESULT_ERROR);
    939 	}
    940 
    941 	kore_split_string(options, " ", argv, 3);
    942 
    943 	if (argv[0] == NULL || argv[1] == NULL) {
    944 		kore_log(LOG_ERR, "invalid privsep context");
    945 		return (KORE_RESULT_ERROR);
    946 	}
    947 
    948 	if (strcmp(argv[1], "{")) {
    949 		kore_log(LOG_ERR, "privsep context not opened correctly");
    950 		return (KORE_RESULT_ERROR);
    951 	}
    952 
    953 	if (!strcmp(argv[0], "worker")) {
    954 		current_privsep = &worker_privsep;
    955 	} else if (!strcmp(argv[0], "keymgr")) {
    956 		current_privsep = &keymgr_privsep;
    957 #if defined(KORE_USE_ACME)
    958 	} else if (!strcmp(argv[0], "acme")) {
    959 		current_privsep = &acme_privsep;
    960 #endif
    961 	} else {
    962 		kore_log(LOG_ERR, "unknown privsep context: %s", argv[0]);
    963 		return (KORE_RESULT_ERROR);
    964 	}
    965 
    966 	return (KORE_RESULT_OK);
    967 }
    968 
    969 static int
    970 configure_privsep_runas(char *user)
    971 {
    972 	if (current_privsep == NULL) {
    973 		kore_log(LOG_ERR, "runas keyword not in privsep context");
    974 		return (KORE_RESULT_ERROR);
    975 	}
    976 
    977 	if (current_privsep->runas != NULL)
    978 		kore_free(current_privsep->runas);
    979 
    980 	current_privsep->runas = kore_strdup(user);
    981 
    982 	return (KORE_RESULT_OK);
    983 }
    984 
    985 static int
    986 configure_privsep_root(char *root)
    987 {
    988 	if (current_privsep == NULL) {
    989 		kore_log(LOG_ERR, "root keyword not in privsep context");
    990 		return (KORE_RESULT_ERROR);
    991 	}
    992 
    993 	if (current_privsep->root != NULL)
    994 		kore_free(current_privsep->root);
    995 
    996 	current_privsep->root = kore_strdup(root);
    997 
    998 	return (KORE_RESULT_OK);
    999 }
   1000 
   1001 static int
   1002 configure_privsep_skip(char *option)
   1003 {
   1004 	if (current_privsep == NULL) {
   1005 		kore_log(LOG_ERR, "skip keyword not in privsep context");
   1006 		return (KORE_RESULT_ERROR);
   1007 	}
   1008 
   1009 	if (!strcmp(option, "chroot")) {
   1010 		current_privsep->skip_chroot = 1;
   1011 	} else {
   1012 		kore_log(LOG_ERR, "unknown skip option '%s'", option);
   1013 		return (KORE_RESULT_ERROR);
   1014 	}
   1015 
   1016 	return (KORE_RESULT_OK);
   1017 }
   1018 
   1019 static int
   1020 configure_domain(char *options)
   1021 {
   1022 	char		*argv[3];
   1023 
   1024 	if (current_domain != NULL) {
   1025 		kore_log(LOG_ERR, "nested domain contexts are not allowed");
   1026 		return (KORE_RESULT_ERROR);
   1027 	}
   1028 
   1029 	kore_split_string(options, " ", argv, 3);
   1030 
   1031 	if (argv[0] == NULL || argv[1] == NULL) {
   1032 		kore_log(LOG_ERR, "invalid domain context");
   1033 		return (KORE_RESULT_ERROR);
   1034 	}
   1035 
   1036 	if (strcmp(argv[1], "{")) {
   1037 		kore_log(LOG_ERR, "domain context not opened correctly");
   1038 		return (KORE_RESULT_ERROR);
   1039 	}
   1040 
   1041 	if (strlen(argv[0]) >= KORE_DOMAINNAME_LEN - 1) {
   1042 		kore_log(LOG_ERR, "domain name '%s' too long", argv[0]);
   1043 		return (KORE_RESULT_ERROR);
   1044 	}
   1045 
   1046 	current_domain = kore_domain_new(argv[0]);
   1047 
   1048 	return (KORE_RESULT_OK);
   1049 }
   1050 
   1051 static int
   1052 configure_attach(char *name)
   1053 {
   1054 	struct kore_server	*srv;
   1055 
   1056 	if (current_domain == NULL) {
   1057 		kore_log(LOG_ERR, "attach keyword not in domain context");
   1058 		return (KORE_RESULT_ERROR);
   1059 	}
   1060 
   1061 	if (current_domain->server != NULL) {
   1062 		kore_log(LOG_ERR, "domain '%s' already attached to server",
   1063 		    current_domain->domain);
   1064 		return (KORE_RESULT_ERROR);
   1065 	}
   1066 
   1067 	if ((srv = kore_server_lookup(name)) == NULL) {
   1068 		kore_log(LOG_ERR, "server '%s' does not exist", name);
   1069 		return (KORE_RESULT_ERROR);
   1070 	}
   1071 
   1072 	if (!kore_domain_attach(current_domain, srv)) {
   1073 		kore_log(LOG_ERR, "failed to attach '%s' to '%s'",
   1074 		    current_domain->domain, name);
   1075 		return (KORE_RESULT_ERROR);
   1076 	}
   1077 
   1078 	return (KORE_RESULT_OK);
   1079 }
   1080 
   1081 #if !defined(KORE_NO_HTTP)
   1082 static int
   1083 configure_static_handler(char *options)
   1084 {
   1085 	kore_log(LOG_NOTICE, "static keyword removed, use route instead");
   1086 	return (KORE_RESULT_ERROR);
   1087 }
   1088 
   1089 static int
   1090 configure_dynamic_handler(char *options)
   1091 {
   1092 	kore_log(LOG_NOTICE, "dynamic keyword removed, use route instead");
   1093 	return (KORE_RESULT_ERROR);
   1094 }
   1095 
   1096 static int
   1097 configure_route(char *options)
   1098 {
   1099 	struct kore_route	*rt;
   1100 	int			type;
   1101 	char			*argv[4];
   1102 
   1103 	if (current_domain == NULL) {
   1104 		kore_log(LOG_ERR, "route keyword not in domain context");
   1105 		return (KORE_RESULT_ERROR);
   1106 	}
   1107 
   1108 	if (current_route != NULL) {
   1109 		kore_log(LOG_ERR, "nested route contexts not allowed");
   1110 		return (KORE_RESULT_ERROR);
   1111 	}
   1112 
   1113 	kore_split_string(options, " ", argv, 4);
   1114 
   1115 	if (argv[1] == NULL || strcmp(argv[1], "{")) {
   1116 		kore_log(LOG_ERR, "invalid route context");
   1117 		return (KORE_RESULT_ERROR);
   1118 	}
   1119 
   1120 	if (*argv[0] == '/')
   1121 		type = HANDLER_TYPE_STATIC;
   1122 	else
   1123 		type = HANDLER_TYPE_DYNAMIC;
   1124 
   1125 	if ((rt = kore_route_create(current_domain, argv[0], type)) == NULL) {
   1126 		kore_log(LOG_ERR,
   1127 		    "failed to create route handler for '%s'", argv[0]);
   1128 		return (KORE_RESULT_ERROR);
   1129 	}
   1130 
   1131 	current_route = rt;
   1132 
   1133 	return (KORE_RESULT_OK);
   1134 }
   1135 
   1136 static int
   1137 configure_route_handler(char *name)
   1138 {
   1139 	if (current_route == NULL) {
   1140 		kore_log(LOG_ERR,
   1141 		    "handler keyword not inside of route context");
   1142 		return (KORE_RESULT_ERROR);
   1143 	}
   1144 
   1145 	kore_route_callback(current_route, name);
   1146 
   1147 	return (KORE_RESULT_OK);
   1148 }
   1149 
   1150 static int
   1151 configure_route_on_headers(char *name)
   1152 {
   1153 	if (current_route == NULL) {
   1154 		kore_log(LOG_ERR,
   1155 		    "on_header keyword not inside of route context");
   1156 		return (KORE_RESULT_ERROR);
   1157 	}
   1158 
   1159 	if ((current_route->on_headers = kore_runtime_getcall(name)) == NULL) {
   1160 		kore_log(LOG_ERR, "on_headers callback '%s' for '%s' not found",
   1161 		    name, current_route->path);
   1162 		return (KORE_RESULT_ERROR);
   1163 	}
   1164 
   1165 	return (KORE_RESULT_OK);
   1166 }
   1167 
   1168 static int
   1169 configure_route_on_body_chunk(char *name)
   1170 {
   1171 	if (current_route == NULL) {
   1172 		kore_log(LOG_ERR,
   1173 		    "on_body_chunk keyword not inside of route context");
   1174 		return (KORE_RESULT_ERROR);
   1175 	}
   1176 
   1177 	current_route->on_body_chunk = kore_runtime_getcall(name);
   1178 	if (current_route->on_body_chunk == NULL) {
   1179 		kore_log(LOG_ERR,
   1180 		    "on_body_chunk callback '%s' for '%s' not found",
   1181 		    name, current_route->path);
   1182 		return (KORE_RESULT_ERROR);
   1183 	}
   1184 
   1185 	return (KORE_RESULT_OK);
   1186 }
   1187 
   1188 static int
   1189 configure_route_on_free(char *name)
   1190 {
   1191 	if (current_route == NULL) {
   1192 		kore_log(LOG_ERR,
   1193 		    "on_free keyword not inside of route context");
   1194 		return (KORE_RESULT_ERROR);
   1195 	}
   1196 
   1197 	if ((current_route->on_free = kore_runtime_getcall(name)) == NULL) {
   1198 		kore_log(LOG_ERR, "on_free callback '%s' for '%s' not found",
   1199 		    name, current_route->path);
   1200 		return (KORE_RESULT_ERROR);
   1201 	}
   1202 
   1203 	return (KORE_RESULT_OK);
   1204 }
   1205 
   1206 static int
   1207 configure_route_authenticate(char *name)
   1208 {
   1209 	if (current_route == NULL) {
   1210 		kore_log(LOG_ERR,
   1211 		    "authenticate keyword not inside of route context");
   1212 		return (KORE_RESULT_ERROR);
   1213 	}
   1214 
   1215 	current_route->auth = kore_auth_lookup(name);
   1216 
   1217 	if (current_route->auth == NULL) {
   1218 		kore_log(LOG_ERR, "no such authentication '%s' for '%s' found",
   1219 		    name, current_route->path);
   1220 		return (KORE_RESULT_ERROR);
   1221 	}
   1222 
   1223 	return (KORE_RESULT_OK);
   1224 }
   1225 
   1226 static int
   1227 configure_route_methods(char *options)
   1228 {
   1229 	int			i, cnt;
   1230 	char			*argv[10];
   1231 
   1232 	if (current_route == NULL) {
   1233 		kore_log(LOG_ERR,
   1234 		    "methods keyword not inside of route context");
   1235 		return (KORE_RESULT_ERROR);
   1236 	}
   1237 
   1238 	cnt = kore_split_string(options, " ", argv, 10);
   1239 	if (cnt < 1) {
   1240 		kore_log(LOG_ERR,
   1241 		    "bad methods option '%s', missing methods", options);
   1242 		return (KORE_RESULT_ERROR);
   1243 	}
   1244 
   1245 	current_route->methods = 0;
   1246 
   1247 	for (i = 0; i < cnt; i++) {
   1248 		if (!strcasecmp(argv[i], "post")) {
   1249 			current_route->methods |= HTTP_METHOD_POST;
   1250 		} else if (!strcasecmp(argv[i], "get")) {
   1251 			current_route->methods |= HTTP_METHOD_GET;
   1252 		} else if (!strcasecmp(argv[i], "put")) {
   1253 			current_route->methods |= HTTP_METHOD_PUT;
   1254 		} else if (!strcasecmp(argv[i], "delete")) {
   1255 			current_route->methods |= HTTP_METHOD_DELETE;
   1256 		} else if (!strcasecmp(argv[i], "head")) {
   1257 			current_route->methods |= HTTP_METHOD_HEAD;
   1258 		} else if (!strcasecmp(argv[i], "patch")) {
   1259 			current_route->methods |= HTTP_METHOD_PATCH;
   1260 		} else if (!strcasecmp(argv[i], "options")) {
   1261 			current_route->methods |= HTTP_METHOD_OPTIONS;
   1262 		} else {
   1263 			kore_log(LOG_ERR, "unknown method: %s in method for %s",
   1264 			    argv[i], current_route->path);
   1265 			return (KORE_RESULT_ERROR);
   1266 		}
   1267 	}
   1268 
   1269 	return (KORE_RESULT_OK);
   1270 }
   1271 
   1272 static int
   1273 configure_return(char *options)
   1274 {
   1275 	char		*argv[3];
   1276 	int		elm, status, err;
   1277 
   1278 	if (current_domain == NULL) {
   1279 		kore_log(LOG_ERR, "return keyword not in domain context");
   1280 		return (KORE_RESULT_ERROR);
   1281 	}
   1282 
   1283 	elm = kore_split_string(options, " ", argv, 3);
   1284 	if (elm != 2) {
   1285 		kore_log(LOG_ERR, "missing parameters for return");
   1286 		return (KORE_RESULT_ERROR);
   1287 	}
   1288 
   1289 	status = kore_strtonum(argv[1], 10, 400, 600, &err);
   1290 	if (err != KORE_RESULT_OK) {
   1291 		kore_log(LOG_ERR,
   1292 		    "invalid status code on return (%s)", argv[1]);
   1293 		return (KORE_RESULT_ERROR);
   1294 	}
   1295 
   1296 	if (!http_redirect_add(current_domain, argv[0], status, NULL)) {
   1297 		kore_log(LOG_ERR, "invalid regex on return path");
   1298 		return (KORE_RESULT_ERROR);
   1299 	}
   1300 
   1301 	return (KORE_RESULT_OK);
   1302 }
   1303 
   1304 static int
   1305 configure_redirect(char *options)
   1306 {
   1307 	char		*argv[4];
   1308 	int		elm, status, err;
   1309 
   1310 	if (current_domain == NULL) {
   1311 		kore_log(LOG_ERR, "redirect keyword not in domain context");
   1312 		return (KORE_RESULT_ERROR);
   1313 	}
   1314 
   1315 	elm = kore_split_string(options, " ", argv, 4);
   1316 	if (elm != 3) {
   1317 		kore_log(LOG_ERR, "missing parameters for redirect");
   1318 		return (KORE_RESULT_ERROR);
   1319 	}
   1320 
   1321 	status = kore_strtonum(argv[1], 10, 300, 399, &err);
   1322 	if (err != KORE_RESULT_OK) {
   1323 		kore_log(LOG_ERR,
   1324 		    "invalid status code on redirect (%s)", argv[1]);
   1325 		return (KORE_RESULT_ERROR);
   1326 	}
   1327 
   1328 	if (!http_redirect_add(current_domain, argv[0], status, argv[2])) {
   1329 		kore_log(LOG_ERR, "invalid regex on redirect path");
   1330 		return (KORE_RESULT_ERROR);
   1331 	}
   1332 
   1333 	return (KORE_RESULT_OK);
   1334 }
   1335 
   1336 static int
   1337 configure_filemap(char *options)
   1338 {
   1339 	char		*argv[4];
   1340 
   1341 	if (current_domain == NULL) {
   1342 		kore_log(LOG_ERR, "filemap keyword not in domain context");
   1343 		return (KORE_RESULT_ERROR);
   1344 	}
   1345 
   1346 	kore_split_string(options, " ", argv, 4);
   1347 
   1348 	if (argv[0] == NULL || argv[1] == NULL) {
   1349 		kore_log(LOG_ERR, "missing parameters for filemap");
   1350 		return (KORE_RESULT_ERROR);
   1351 	}
   1352 
   1353 	if (kore_filemap_create(current_domain,
   1354 	    argv[1], argv[0], argv[2]) == NULL) {
   1355 		kore_log(LOG_ERR, "cannot create filemap for %s", argv[1]);
   1356 		return (KORE_RESULT_ERROR);
   1357 	}
   1358 
   1359 	return (KORE_RESULT_OK);
   1360 }
   1361 
   1362 static int
   1363 configure_accesslog(char *path)
   1364 {
   1365 	if (current_domain == NULL) {
   1366 		kore_log(LOG_ERR, "accesslog not specified in domain context");
   1367 		return (KORE_RESULT_ERROR);
   1368 	}
   1369 
   1370 	if (current_domain->accesslog != -1) {
   1371 		kore_log(LOG_ERR, "domain '%s' already has an open accesslog",
   1372 		    current_domain->domain);
   1373 		return (KORE_RESULT_ERROR);
   1374 	}
   1375 
   1376 	current_domain->accesslog = open(path,
   1377 	    O_CREAT | O_APPEND | O_WRONLY,
   1378 	    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
   1379 	if (current_domain->accesslog == -1) {
   1380 		kore_log(LOG_ERR, "accesslog open(%s): %s", path, errno_s);
   1381 		return (KORE_RESULT_ERROR);
   1382 	}
   1383 
   1384 	return (KORE_RESULT_OK);
   1385 }
   1386 
   1387 static int
   1388 configure_filemap_ext(char *ext)
   1389 {
   1390 	kore_free(kore_filemap_ext);
   1391 	kore_filemap_ext = kore_strdup(ext);
   1392 
   1393 	return (KORE_RESULT_OK);
   1394 }
   1395 
   1396 static int
   1397 configure_filemap_index(char *index)
   1398 {
   1399 	kore_free(kore_filemap_index);
   1400 	kore_filemap_index = kore_strdup(index);
   1401 
   1402 	return (KORE_RESULT_OK);
   1403 }
   1404 
   1405 static int
   1406 configure_http_media_type(char *type)
   1407 {
   1408 	int		i;
   1409 	char		*extensions, *ext[10];
   1410 
   1411 	extensions = strchr(type, ' ');
   1412 	if (extensions == NULL) {
   1413 		kore_log(LOG_ERR, "bad http_media_type value '%s'", type);
   1414 		return (KORE_RESULT_ERROR);
   1415 	}
   1416 
   1417 	*(extensions)++ = '\0';
   1418 
   1419 	kore_split_string(extensions, " \t", ext, 10);
   1420 	for (i = 0; ext[i] != NULL; i++) {
   1421 		if (!http_media_register(ext[i], type)) {
   1422 			kore_log(LOG_ERR,
   1423 			    "duplicate extension found '%s'", ext[i]);
   1424 			return (KORE_RESULT_ERROR);
   1425 		}
   1426 	}
   1427 
   1428 	if (i == 0) {
   1429 		kore_log(LOG_ERR, "missing extensions in '%s'", type);
   1430 		return (KORE_RESULT_ERROR);
   1431 	}
   1432 
   1433 	return (KORE_RESULT_OK);
   1434 }
   1435 
   1436 static int
   1437 configure_http_header_max(char *option)
   1438 {
   1439 	int		err;
   1440 
   1441 	http_header_max = kore_strtonum(option, 10, 1, 65535, &err);
   1442 	if (err != KORE_RESULT_OK) {
   1443 		kore_log(LOG_ERR, "bad http_header_max value '%s'", option);
   1444 		return (KORE_RESULT_ERROR);
   1445 	}
   1446 
   1447 	return (KORE_RESULT_OK);
   1448 }
   1449 
   1450 static int
   1451 configure_http_header_timeout(char *option)
   1452 {
   1453 	int		err;
   1454 
   1455 	http_header_timeout = kore_strtonum(option, 10, 1, 65535, &err);
   1456 	if (err != KORE_RESULT_OK) {
   1457 		kore_log(LOG_ERR, "bad http_header_timeout value '%s'", option);
   1458 		return (KORE_RESULT_ERROR);
   1459 	}
   1460 
   1461 	return (KORE_RESULT_OK);
   1462 }
   1463 
   1464 static int
   1465 configure_http_body_max(char *option)
   1466 {
   1467 	int		err;
   1468 
   1469 	http_body_max = kore_strtonum(option, 10, 0, LONG_MAX, &err);
   1470 	if (err != KORE_RESULT_OK) {
   1471 		kore_log(LOG_ERR, "bad http_body_max value '%s'", option);
   1472 		return (KORE_RESULT_ERROR);
   1473 	}
   1474 
   1475 	return (KORE_RESULT_OK);
   1476 }
   1477 
   1478 static int
   1479 configure_http_body_timeout(char *option)
   1480 {
   1481 	int		err;
   1482 
   1483 	http_body_timeout = kore_strtonum(option, 10, 1, 65535, &err);
   1484 	if (err != KORE_RESULT_OK) {
   1485 		kore_log(LOG_ERR, "bad http_body_timeout value '%s'", option);
   1486 		return (KORE_RESULT_ERROR);
   1487 	}
   1488 
   1489 	return (KORE_RESULT_OK);
   1490 }
   1491 
   1492 static int
   1493 configure_http_body_disk_offload(char *option)
   1494 {
   1495 	int		err;
   1496 
   1497 	http_body_disk_offload = kore_strtonum(option, 10, 0, LONG_MAX, &err);
   1498 	if (err != KORE_RESULT_OK) {
   1499 		kore_log(LOG_ERR,
   1500 		    "bad http_body_disk_offload value '%s'", option);
   1501 		return (KORE_RESULT_ERROR);
   1502 	}
   1503 
   1504 	return (KORE_RESULT_OK);
   1505 }
   1506 
   1507 static int
   1508 configure_http_body_disk_path(char *path)
   1509 {
   1510 	if (strcmp(http_body_disk_path, HTTP_BODY_DISK_PATH))
   1511 		kore_free(http_body_disk_path);
   1512 
   1513 	http_body_disk_path = kore_strdup(path);
   1514 	return (KORE_RESULT_OK);
   1515 }
   1516 
   1517 static int
   1518 configure_http_server_version(char *version)
   1519 {
   1520 	http_server_version(version);
   1521 
   1522 	return (KORE_RESULT_OK);
   1523 }
   1524 
   1525 static int
   1526 configure_http_pretty_error(char *yesno)
   1527 {
   1528 	if (!strcmp(yesno, "no")) {
   1529 		http_pretty_error = 0;
   1530 	} else if (!strcmp(yesno, "yes")) {
   1531 		http_pretty_error = 1;
   1532 	} else {
   1533 		kore_log(LOG_ERR,
   1534 		    "invalid '%s' for yes|no http_pretty_error option", yesno);
   1535 		return (KORE_RESULT_ERROR);
   1536 	}
   1537 
   1538 	return (KORE_RESULT_OK);
   1539 }
   1540 
   1541 static int
   1542 configure_http_hsts_enable(char *option)
   1543 {
   1544 	int		err;
   1545 
   1546 	http_hsts_enable = kore_strtonum(option, 10, 0, LONG_MAX, &err);
   1547 	if (err != KORE_RESULT_OK) {
   1548 		kore_log(LOG_ERR, "bad http_hsts_enable value '%s'", option);
   1549 		return (KORE_RESULT_ERROR);
   1550 	}
   1551 
   1552 	return (KORE_RESULT_OK);
   1553 }
   1554 
   1555 static int
   1556 configure_http_keepalive_time(char *option)
   1557 {
   1558 	int		err;
   1559 
   1560 	http_keepalive_time = kore_strtonum(option, 10, 0, USHRT_MAX, &err);
   1561 	if (err != KORE_RESULT_OK) {
   1562 		kore_log(LOG_ERR,
   1563 		    "bad http_keepalive_time value '%s'", option);
   1564 		return (KORE_RESULT_ERROR);
   1565 	}
   1566 
   1567 	return (KORE_RESULT_OK);
   1568 }
   1569 
   1570 static int
   1571 configure_http_request_ms(char *option)
   1572 {
   1573 	int		err;
   1574 
   1575 	http_request_ms = kore_strtonum(option, 10, 0, UINT_MAX, &err);
   1576 	if (err != KORE_RESULT_OK) {
   1577 		kore_log(LOG_ERR, "bad http_request_ms value '%s'", option);
   1578 		return (KORE_RESULT_ERROR);
   1579 	}
   1580 
   1581 	return (KORE_RESULT_OK);
   1582 }
   1583 
   1584 static int
   1585 configure_http_request_limit(char *option)
   1586 {
   1587 	int		err;
   1588 
   1589 	http_request_limit = kore_strtonum(option, 10, 0, UINT_MAX, &err);
   1590 	if (err != KORE_RESULT_OK) {
   1591 		kore_log(LOG_ERR, "bad http_request_limit value '%s'", option);
   1592 		return (KORE_RESULT_ERROR);
   1593 	}
   1594 
   1595 	return (KORE_RESULT_OK);
   1596 }
   1597 
   1598 static int
   1599 configure_validator(char *name)
   1600 {
   1601 	u_int8_t	type;
   1602 	char		*tname, *value;
   1603 
   1604 	if ((tname = strchr(name, ' ')) == NULL) {
   1605 		kore_log(LOG_ERR, "missing validator name");
   1606 		return (KORE_RESULT_ERROR);
   1607 	}
   1608 
   1609 	*(tname)++ = '\0';
   1610 	tname = kore_text_trim(tname, strlen(tname));
   1611 	if ((value = strchr(tname, ' ')) == NULL) {
   1612 		kore_log(LOG_ERR, "missing validator value");
   1613 		return (KORE_RESULT_ERROR);
   1614 	}
   1615 
   1616 	*(value)++ = '\0';
   1617 	value = kore_text_trim(value, strlen(value));
   1618 
   1619 	if (!strcmp(tname, "regex")) {
   1620 		type = KORE_VALIDATOR_TYPE_REGEX;
   1621 	} else if (!strcmp(tname, "function")) {
   1622 		type = KORE_VALIDATOR_TYPE_FUNCTION;
   1623 	} else {
   1624 		kore_log(LOG_ERR,
   1625 		    "bad type '%s' for validator '%s'", tname, name);
   1626 		return (KORE_RESULT_ERROR);
   1627 	}
   1628 
   1629 	if (!kore_validator_add(name, type, value)) {
   1630 		kore_log(LOG_ERR, "bad validator specified for '%s'", name);
   1631 		return (KORE_RESULT_ERROR);
   1632 	}
   1633 
   1634 	return (KORE_RESULT_OK);
   1635 }
   1636 
   1637 static int
   1638 configure_validate(char *options)
   1639 {
   1640 	struct kore_validator		*val;
   1641 	struct kore_route_params	*param;
   1642 	char				*method, *argv[4];
   1643 	int				flags, http_method;
   1644 
   1645 	if (kore_split_string(options, " ", argv, 4) != 3) {
   1646 		kore_log(LOG_ERR,
   1647 		    "validate keyword needs 3 args: method param validator");
   1648 		return (KORE_RESULT_ERROR);
   1649 	}
   1650 
   1651 	flags = 0;
   1652 
   1653 	if ((method = strchr(argv[0], ':')) != NULL) {
   1654 		*(method)++ = '\0';
   1655 		if (!strcasecmp(argv[0], "qs")) {
   1656 			flags = KORE_PARAMS_QUERY_STRING;
   1657 		} else {
   1658 			kore_log(LOG_ERR,
   1659 			    "unknown validate method prefix '%s' for '%s'",
   1660 			    argv[0], current_route->path);
   1661 			return (KORE_RESULT_ERROR);
   1662 		}
   1663 	} else {
   1664 		method = argv[0];
   1665 	}
   1666 
   1667 	if ((val = kore_validator_lookup(argv[2])) == NULL) {
   1668 		kore_log(LOG_ERR, "unknown validator '%s'", argv[2]);
   1669 		return (KORE_RESULT_ERROR);
   1670 	}
   1671 
   1672 	if (!strcasecmp(method, "post")) {
   1673 		http_method = HTTP_METHOD_POST;
   1674 	} else if (!strcasecmp(method, "get")) {
   1675 		http_method = HTTP_METHOD_GET;
   1676 		/* Let params get /foo {} imply qs:get automatically. */
   1677 		flags |= KORE_PARAMS_QUERY_STRING;
   1678 	} else if (!strcasecmp(method, "put")) {
   1679 		http_method = HTTP_METHOD_PUT;
   1680 	} else if (!strcasecmp(method, "delete")) {
   1681 		http_method = HTTP_METHOD_DELETE;
   1682 	} else if (!strcasecmp(method, "head")) {
   1683 		http_method = HTTP_METHOD_HEAD;
   1684 	} else if (!strcasecmp(method, "patch")) {
   1685 		http_method = HTTP_METHOD_PATCH;
   1686 	} else {
   1687 		kore_log(LOG_ERR, "unknown method: %s in validator for %s",
   1688 		    method, current_route->path);
   1689 		return (KORE_RESULT_ERROR);
   1690 	}
   1691 
   1692 	if (!(current_route->methods & http_method)) {
   1693 		kore_log(LOG_ERR, "method '%s' not enabled for route '%s'",
   1694 		    method, current_route->path);
   1695 		return (KORE_RESULT_ERROR);
   1696 	}
   1697 
   1698 	param = kore_calloc(1, sizeof(*param));
   1699 
   1700 	param->flags = flags;
   1701 	param->validator = val;
   1702 	param->method = http_method;
   1703 	param->name = kore_strdup(argv[1]);
   1704 
   1705 	TAILQ_INSERT_TAIL(&current_route->params, param, list);
   1706 
   1707 	return (KORE_RESULT_OK);
   1708 }
   1709 
   1710 static int
   1711 configure_authentication(char *options)
   1712 {
   1713 	char		*argv[3];
   1714 
   1715 	if (current_auth != NULL) {
   1716 		kore_log(LOG_ERR, "previous authentication block not closed");
   1717 		return (KORE_RESULT_ERROR);
   1718 	}
   1719 
   1720 	kore_split_string(options, " ", argv, 3);
   1721 	if (argv[1] == NULL) {
   1722 		kore_log(LOG_ERR, "missing name for authentication block");
   1723 		return (KORE_RESULT_ERROR);
   1724 	}
   1725 
   1726 	if (strcmp(argv[1], "{")) {
   1727 		kore_log(LOG_ERR, "missing { for authentication block");
   1728 		return (KORE_RESULT_ERROR);
   1729 	}
   1730 
   1731 	if (!kore_auth_new(argv[0]))
   1732 		return (KORE_RESULT_ERROR);
   1733 
   1734 	current_auth = kore_auth_lookup(argv[0]);
   1735 
   1736 	return (KORE_RESULT_OK);
   1737 }
   1738 
   1739 static int
   1740 configure_authentication_type(char *option)
   1741 {
   1742 	if (current_auth == NULL) {
   1743 		kore_log(LOG_ERR,
   1744 		    "authentication_type keyword not in correct context");
   1745 		return (KORE_RESULT_ERROR);
   1746 	}
   1747 
   1748 	if (!strcmp(option, "cookie")) {
   1749 		current_auth->type = KORE_AUTH_TYPE_COOKIE;
   1750 	} else if (!strcmp(option, "header")) {
   1751 		current_auth->type = KORE_AUTH_TYPE_HEADER;
   1752 	} else if (!strcmp(option, "request")) {
   1753 		current_auth->type = KORE_AUTH_TYPE_REQUEST;
   1754 	} else {
   1755 		kore_log(LOG_ERR, "unknown authentication type '%s'", option);
   1756 		return (KORE_RESULT_ERROR);
   1757 	}
   1758 
   1759 	return (KORE_RESULT_OK);
   1760 }
   1761 
   1762 static int
   1763 configure_authentication_value(char *option)
   1764 {
   1765 	if (current_auth == NULL) {
   1766 		kore_log(LOG_ERR,
   1767 		    "authentication_value keyword not in correct context");
   1768 		return (KORE_RESULT_ERROR);
   1769 	}
   1770 
   1771 	if (current_auth->value != NULL)
   1772 		kore_free(current_auth->value);
   1773 	current_auth->value = kore_strdup(option);
   1774 
   1775 	return (KORE_RESULT_OK);
   1776 }
   1777 
   1778 static int
   1779 configure_authentication_validator(char *validator)
   1780 {
   1781 	struct kore_validator		*val;
   1782 
   1783 	if (current_auth == NULL) {
   1784 		kore_log(LOG_ERR,
   1785 		    "authentication_validator not in correct context");
   1786 		return (KORE_RESULT_ERROR);
   1787 	}
   1788 
   1789 	if ((val = kore_validator_lookup(validator)) == NULL) {
   1790 		kore_log(LOG_ERR,
   1791 		    "authentication validator '%s' not found", validator);
   1792 		return (KORE_RESULT_ERROR);
   1793 	}
   1794 
   1795 	current_auth->validator = val;
   1796 
   1797 	return (KORE_RESULT_OK);
   1798 }
   1799 
   1800 static int
   1801 configure_authentication_uri(char *uri)
   1802 {
   1803 	if (current_auth == NULL) {
   1804 		kore_log(LOG_ERR,
   1805 		    "authentication_uri keyword not in correct context");
   1806 		return (KORE_RESULT_ERROR);
   1807 	}
   1808 
   1809 	if (current_auth->redirect != NULL)
   1810 		kore_free(current_auth->redirect);
   1811 	current_auth->redirect = kore_strdup(uri);
   1812 
   1813 	return (KORE_RESULT_OK);
   1814 }
   1815 
   1816 static int
   1817 configure_websocket_maxframe(char *option)
   1818 {
   1819 	int	err;
   1820 
   1821 	kore_websocket_maxframe = kore_strtonum64(option, 1, &err);
   1822 	if (err != KORE_RESULT_OK) {
   1823 		kore_log(LOG_ERR,
   1824 		    "bad kore_websocket_maxframe value '%s'", option);
   1825 		return (KORE_RESULT_ERROR);
   1826 	}
   1827 
   1828 	return (KORE_RESULT_OK);
   1829 }
   1830 
   1831 static int
   1832 configure_websocket_timeout(char *option)
   1833 {
   1834 	int	err;
   1835 
   1836 	kore_websocket_timeout = kore_strtonum64(option, 1, &err);
   1837 	if (err != KORE_RESULT_OK) {
   1838 		kore_log(LOG_ERR,
   1839 		    "bad kore_websocket_timeout value '%s'", option);
   1840 		return (KORE_RESULT_ERROR);
   1841 	}
   1842 
   1843 	kore_websocket_timeout = kore_websocket_timeout * 1000;
   1844 
   1845 	return (KORE_RESULT_OK);
   1846 }
   1847 
   1848 #endif /* !KORE_NO_HTTP */
   1849 
   1850 static int
   1851 configure_logfile(char *path)
   1852 {
   1853 	kore_log_file(path);
   1854 	return (KORE_RESULT_OK);
   1855 }
   1856 
   1857 static int
   1858 configure_workers(char *option)
   1859 {
   1860 	int		err;
   1861 
   1862 	worker_count = kore_strtonum(option, 10, 1, KORE_WORKER_MAX, &err);
   1863 	if (err != KORE_RESULT_OK) {
   1864 		kore_log(LOG_ERR, "bad value for worker '%s'", option);
   1865 		return (KORE_RESULT_ERROR);
   1866 	}
   1867 
   1868 	return (KORE_RESULT_OK);
   1869 }
   1870 
   1871 static int
   1872 configure_pidfile(char *path)
   1873 {
   1874 	if (strcmp(kore_pidfile, KORE_PIDFILE_DEFAULT))
   1875 		kore_free(kore_pidfile);
   1876 	kore_pidfile = kore_strdup(path);
   1877 
   1878 	return (KORE_RESULT_OK);
   1879 }
   1880 
   1881 static int
   1882 configure_no_accept(char *option)
   1883 {
   1884 	int			err, idx;
   1885 
   1886 	idx = kore_strtonum(option, 10, 1, KORE_WORKER_MAX, &err);
   1887 	if (err != KORE_RESULT_OK) {
   1888 		kore_log(LOG_ERR,
   1889 		    "bad value for worker_no_accept '%s'", option);
   1890 		return (KORE_RESULT_ERROR);
   1891 	}
   1892 
   1893 	kore_worker_no_accept(idx);
   1894 
   1895 	return (KORE_RESULT_OK);
   1896 }
   1897 
   1898 static int
   1899 configure_max_connections(char *option)
   1900 {
   1901 	int		err;
   1902 
   1903 	worker_max_connections = kore_strtonum(option, 10, 1, UINT_MAX, &err);
   1904 	if (err != KORE_RESULT_OK) {
   1905 		kore_log(LOG_ERR,
   1906 		    "bad value for worker_max_connections '%s'", option);
   1907 		return (KORE_RESULT_ERROR);
   1908 	}
   1909 
   1910 	return (KORE_RESULT_OK);
   1911 }
   1912 
   1913 static int
   1914 configure_rlimit_nofiles(char *option)
   1915 {
   1916 	int		err;
   1917 
   1918 	worker_rlimit_nofiles = kore_strtonum(option, 10, 1, UINT_MAX, &err);
   1919 	if (err != KORE_RESULT_OK) {
   1920 		kore_log(LOG_ERR,
   1921 		    "bad value for worker_rlimit_nofiles '%s'", option);
   1922 		return (KORE_RESULT_ERROR);
   1923 	}
   1924 
   1925 	return (KORE_RESULT_OK);
   1926 }
   1927 
   1928 static int
   1929 configure_accept_threshold(char *option)
   1930 {
   1931 	int		err;
   1932 
   1933 	worker_accept_threshold = kore_strtonum(option, 0, 1, UINT_MAX, &err);
   1934 	if (err != KORE_RESULT_OK) {
   1935 		kore_log(LOG_ERR,
   1936 		    "bad value for worker_accept_threshold '%s'\n", option);
   1937 		return (KORE_RESULT_ERROR);
   1938 	}
   1939 
   1940 	return (KORE_RESULT_OK);
   1941 }
   1942 
   1943 static int
   1944 configure_death_policy(char *option)
   1945 {
   1946 	if (!strcmp(option, "restart")) {
   1947 		worker_policy = KORE_WORKER_POLICY_RESTART;
   1948 	} else if (!strcmp(option, "terminate")) {
   1949 		worker_policy = KORE_WORKER_POLICY_TERMINATE;
   1950 	} else {
   1951 		kore_log(LOG_ERR,
   1952 		    "bad value for worker_death_policy '%s'\n", option);
   1953 		return (KORE_RESULT_ERROR);
   1954 	}
   1955 
   1956 	return (KORE_RESULT_OK);
   1957 }
   1958 
   1959 static int
   1960 configure_set_affinity(char *option)
   1961 {
   1962 	int		err;
   1963 
   1964 	worker_set_affinity = kore_strtonum(option, 10, 0, 1, &err);
   1965 	if (err != KORE_RESULT_OK) {
   1966 		kore_log(LOG_ERR,
   1967 		    "bad value for worker_set_affinity '%s'", option);
   1968 		return (KORE_RESULT_ERROR);
   1969 	}
   1970 
   1971 	return (KORE_RESULT_OK);
   1972 }
   1973 
   1974 static int
   1975 configure_socket_backlog(char *option)
   1976 {
   1977 	int		err;
   1978 
   1979 	kore_socket_backlog = kore_strtonum(option, 10, 0, UINT_MAX, &err);
   1980 	if (err != KORE_RESULT_OK) {
   1981 		kore_log(LOG_ERR, "bad socket_backlog value: '%s'", option);
   1982 		return (KORE_RESULT_ERROR);
   1983 	}
   1984 
   1985 	return (KORE_RESULT_OK);
   1986 }
   1987 
   1988 #if defined(KORE_USE_PGSQL)
   1989 static int
   1990 configure_pgsql_conn_max(char *option)
   1991 {
   1992 	int		err;
   1993 
   1994 	pgsql_conn_max = kore_strtonum(option, 10, 0, USHRT_MAX, &err);
   1995 	if (err != KORE_RESULT_OK) {
   1996 		kore_log(LOG_ERR, "bad value for pgsql_conn_max '%s'", option);
   1997 		return (KORE_RESULT_ERROR);
   1998 	}
   1999 
   2000 	return (KORE_RESULT_OK);
   2001 }
   2002 
   2003 static int
   2004 configure_pgsql_queue_limit(char *option)
   2005 {
   2006 	int		err;
   2007 
   2008 	pgsql_queue_limit = kore_strtonum(option, 10, 0, UINT_MAX, &err);
   2009 	if (err != KORE_RESULT_OK) {
   2010 		kore_log(LOG_ERR,
   2011 		    "bad value for pgsql_queue_limit '%s'", option);
   2012 		return (KORE_RESULT_ERROR);
   2013 	}
   2014 
   2015 	return (KORE_RESULT_OK);
   2016 }
   2017 #endif
   2018 
   2019 #if defined(KORE_USE_TASKS)
   2020 static int
   2021 configure_task_threads(char *option)
   2022 {
   2023 	int		err;
   2024 
   2025 	kore_task_threads = kore_strtonum(option, 10, 0, UCHAR_MAX, &err);
   2026 	if (err != KORE_RESULT_OK) {
   2027 		kore_log(LOG_ERR, "bad value for task_threads: '%s'", option);
   2028 		return (KORE_RESULT_ERROR);
   2029 	}
   2030 
   2031 	return (KORE_RESULT_OK);
   2032 }
   2033 #endif
   2034 
   2035 static int
   2036 configure_deployment(char *value)
   2037 {
   2038 	if (!strcmp(value, "docker")) {
   2039 		kore_foreground = 1;
   2040 		skip_runas = 0;
   2041 		skip_chroot = 0;
   2042 	} else if (!strcmp(value, "dev") || !strcmp(value, "development")) {
   2043 		kore_foreground = 1;
   2044 		skip_runas = 1;
   2045 		skip_chroot = 1;
   2046 	} else if (!strcmp(value, "production")) {
   2047 		kore_foreground = 0;
   2048 		skip_runas = 0;
   2049 		skip_chroot = 0;
   2050 	} else {
   2051 		kore_log(LOG_NOTICE,
   2052 		    "kore.config.deployment: bad value '%s'", value);
   2053 		return (KORE_RESULT_ERROR);
   2054 	}
   2055 
   2056 	return (KORE_RESULT_OK);
   2057 }
   2058 
   2059 #if defined(KORE_USE_PYTHON)
   2060 static int
   2061 configure_python_path(char *path)
   2062 {
   2063 	kore_python_path(path);
   2064 
   2065 	return (KORE_RESULT_OK);
   2066 }
   2067 
   2068 static int
   2069 configure_python_import(char *module)
   2070 {
   2071 	char		*argv[3];
   2072 
   2073 	kore_split_string(module, " ", argv, 3);
   2074 	if (argv[0] == NULL)
   2075 		return (KORE_RESULT_ERROR);
   2076 
   2077 	kore_module_load(argv[0], argv[1], KORE_MODULE_PYTHON);
   2078 	return (KORE_RESULT_OK);
   2079 }
   2080 #endif
   2081 
   2082 #if defined(KORE_USE_PLATFORM_PLEDGE)
   2083 static int
   2084 configure_add_pledge(char *pledge)
   2085 {
   2086 	kore_platform_add_pledge(pledge);
   2087 
   2088 	return (KORE_RESULT_OK);
   2089 }
   2090 #endif
   2091 
   2092 #if defined(KORE_USE_CURL)
   2093 static int
   2094 configure_curl_recv_max(char *option)
   2095 {
   2096 	int		err;
   2097 
   2098 	kore_curl_recv_max = kore_strtonum64(option, 1, &err);
   2099 	if (err != KORE_RESULT_OK) {
   2100 		kore_log(LOG_ERR, "bad curl_recv_max value '%s'\n", option);
   2101 		return (KORE_RESULT_ERROR);
   2102 	}
   2103 
   2104 	return (KORE_RESULT_OK);
   2105 }
   2106 
   2107 static int
   2108 configure_curl_timeout(char *option)
   2109 {
   2110 	int		err;
   2111 
   2112 	kore_curl_timeout = kore_strtonum(option, 10, 0, USHRT_MAX, &err);
   2113 	if (err != KORE_RESULT_OK) {
   2114 		kore_log(LOG_ERR, "bad kore_curl_timeout value: '%s'", option);
   2115 		return (KORE_RESULT_ERROR);
   2116 	}
   2117 
   2118 	return (KORE_RESULT_OK);
   2119 }
   2120 #endif
   2121 
   2122 #if defined(__linux__)
   2123 static int
   2124 configure_seccomp_tracing(char *opt)
   2125 {
   2126 	if (!strcmp(opt, "yes")) {
   2127 		kore_seccomp_tracing = 1;
   2128 	} else if (!strcmp(opt, "no")) {
   2129 		kore_seccomp_tracing = 0;
   2130 	} else {
   2131 		kore_log(LOG_ERR,
   2132 		    "bad seccomp_tracing value '%s' (expected yes|no)\n", opt);
   2133 		return (KORE_RESULT_ERROR);
   2134 	}
   2135 
   2136 	return (KORE_RESULT_OK);
   2137 }
   2138 #endif