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 (50407B)



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