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



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