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 ¤t_domain->certkey, ¤t_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(¤t_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