config.c (49339B)
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 if (!strcasecmp(argv[i], "options")) {
1259 current_route->methods |= HTTP_METHOD_OPTIONS;
1260 } else {
1261 kore_log(LOG_ERR, "unknown method: %s in method for %s",
1262 argv[i], current_route->path);
1263 return (KORE_RESULT_ERROR);
1264 }
1265 }
1266
1267 return (KORE_RESULT_OK);
1268 }
1269
1270 static int
1271 configure_return(char *options)
1272 {
1273 char *argv[3];
1274 int elm, status, err;
1275
1276 if (current_domain == NULL) {
1277 kore_log(LOG_ERR, "return keyword not in domain context");
1278 return (KORE_RESULT_ERROR);
1279 }
1280
1281 elm = kore_split_string(options, " ", argv, 3);
1282 if (elm != 2) {
1283 kore_log(LOG_ERR, "missing parameters for return");
1284 return (KORE_RESULT_ERROR);
1285 }
1286
1287 status = kore_strtonum(argv[1], 10, 400, 600, &err);
1288 if (err != KORE_RESULT_OK) {
1289 kore_log(LOG_ERR,
1290 "invalid status code on return (%s)", argv[1]);
1291 return (KORE_RESULT_ERROR);
1292 }
1293
1294 if (!http_redirect_add(current_domain, argv[0], status, NULL)) {
1295 kore_log(LOG_ERR, "invalid regex on return path");
1296 return (KORE_RESULT_ERROR);
1297 }
1298
1299 return (KORE_RESULT_OK);
1300 }
1301
1302 static int
1303 configure_redirect(char *options)
1304 {
1305 char *argv[4];
1306 int elm, status, err;
1307
1308 if (current_domain == NULL) {
1309 kore_log(LOG_ERR, "redirect keyword not in domain context");
1310 return (KORE_RESULT_ERROR);
1311 }
1312
1313 elm = kore_split_string(options, " ", argv, 4);
1314 if (elm != 3) {
1315 kore_log(LOG_ERR, "missing parameters for redirect");
1316 return (KORE_RESULT_ERROR);
1317 }
1318
1319 status = kore_strtonum(argv[1], 10, 300, 399, &err);
1320 if (err != KORE_RESULT_OK) {
1321 kore_log(LOG_ERR,
1322 "invalid status code on redirect (%s)", argv[1]);
1323 return (KORE_RESULT_ERROR);
1324 }
1325
1326 if (!http_redirect_add(current_domain, argv[0], status, argv[2])) {
1327 kore_log(LOG_ERR, "invalid regex on redirect path");
1328 return (KORE_RESULT_ERROR);
1329 }
1330
1331 return (KORE_RESULT_OK);
1332 }
1333
1334 static int
1335 configure_filemap(char *options)
1336 {
1337 char *argv[4];
1338
1339 if (current_domain == NULL) {
1340 kore_log(LOG_ERR, "filemap keyword not in domain context");
1341 return (KORE_RESULT_ERROR);
1342 }
1343
1344 kore_split_string(options, " ", argv, 4);
1345
1346 if (argv[0] == NULL || argv[1] == NULL) {
1347 kore_log(LOG_ERR, "missing parameters for filemap");
1348 return (KORE_RESULT_ERROR);
1349 }
1350
1351 if (kore_filemap_create(current_domain,
1352 argv[1], argv[0], argv[2]) == NULL) {
1353 kore_log(LOG_ERR, "cannot create filemap for %s", argv[1]);
1354 return (KORE_RESULT_ERROR);
1355 }
1356
1357 return (KORE_RESULT_OK);
1358 }
1359
1360 static int
1361 configure_accesslog(char *path)
1362 {
1363 if (current_domain == NULL) {
1364 kore_log(LOG_ERR, "accesslog not specified in domain context");
1365 return (KORE_RESULT_ERROR);
1366 }
1367
1368 if (current_domain->accesslog != -1) {
1369 kore_log(LOG_ERR, "domain '%s' already has an open accesslog",
1370 current_domain->domain);
1371 return (KORE_RESULT_ERROR);
1372 }
1373
1374 current_domain->accesslog = open(path,
1375 O_CREAT | O_APPEND | O_WRONLY,
1376 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
1377 if (current_domain->accesslog == -1) {
1378 kore_log(LOG_ERR, "accesslog open(%s): %s", path, errno_s);
1379 return (KORE_RESULT_ERROR);
1380 }
1381
1382 return (KORE_RESULT_OK);
1383 }
1384
1385 static int
1386 configure_filemap_ext(char *ext)
1387 {
1388 kore_free(kore_filemap_ext);
1389 kore_filemap_ext = kore_strdup(ext);
1390
1391 return (KORE_RESULT_OK);
1392 }
1393
1394 static int
1395 configure_filemap_index(char *index)
1396 {
1397 kore_free(kore_filemap_index);
1398 kore_filemap_index = kore_strdup(index);
1399
1400 return (KORE_RESULT_OK);
1401 }
1402
1403 static int
1404 configure_http_media_type(char *type)
1405 {
1406 int i;
1407 char *extensions, *ext[10];
1408
1409 extensions = strchr(type, ' ');
1410 if (extensions == NULL) {
1411 kore_log(LOG_ERR, "bad http_media_type value '%s'", type);
1412 return (KORE_RESULT_ERROR);
1413 }
1414
1415 *(extensions)++ = '\0';
1416
1417 kore_split_string(extensions, " \t", ext, 10);
1418 for (i = 0; ext[i] != NULL; i++) {
1419 if (!http_media_register(ext[i], type)) {
1420 kore_log(LOG_ERR,
1421 "duplicate extension found '%s'", ext[i]);
1422 return (KORE_RESULT_ERROR);
1423 }
1424 }
1425
1426 if (i == 0) {
1427 kore_log(LOG_ERR, "missing extensions in '%s'", type);
1428 return (KORE_RESULT_ERROR);
1429 }
1430
1431 return (KORE_RESULT_OK);
1432 }
1433
1434 static int
1435 configure_http_header_max(char *option)
1436 {
1437 int err;
1438
1439 http_header_max = kore_strtonum(option, 10, 1, 65535, &err);
1440 if (err != KORE_RESULT_OK) {
1441 kore_log(LOG_ERR, "bad http_header_max value '%s'", option);
1442 return (KORE_RESULT_ERROR);
1443 }
1444
1445 return (KORE_RESULT_OK);
1446 }
1447
1448 static int
1449 configure_http_header_timeout(char *option)
1450 {
1451 int err;
1452
1453 http_header_timeout = kore_strtonum(option, 10, 1, 65535, &err);
1454 if (err != KORE_RESULT_OK) {
1455 kore_log(LOG_ERR, "bad http_header_timeout value '%s'", option);
1456 return (KORE_RESULT_ERROR);
1457 }
1458
1459 return (KORE_RESULT_OK);
1460 }
1461
1462 static int
1463 configure_http_body_max(char *option)
1464 {
1465 int err;
1466
1467 http_body_max = kore_strtonum(option, 10, 0, LONG_MAX, &err);
1468 if (err != KORE_RESULT_OK) {
1469 kore_log(LOG_ERR, "bad http_body_max value '%s'", option);
1470 return (KORE_RESULT_ERROR);
1471 }
1472
1473 return (KORE_RESULT_OK);
1474 }
1475
1476 static int
1477 configure_http_body_timeout(char *option)
1478 {
1479 int err;
1480
1481 http_body_timeout = kore_strtonum(option, 10, 1, 65535, &err);
1482 if (err != KORE_RESULT_OK) {
1483 kore_log(LOG_ERR, "bad http_body_timeout value '%s'", option);
1484 return (KORE_RESULT_ERROR);
1485 }
1486
1487 return (KORE_RESULT_OK);
1488 }
1489
1490 static int
1491 configure_http_body_disk_offload(char *option)
1492 {
1493 int err;
1494
1495 http_body_disk_offload = kore_strtonum(option, 10, 0, LONG_MAX, &err);
1496 if (err != KORE_RESULT_OK) {
1497 kore_log(LOG_ERR,
1498 "bad http_body_disk_offload value '%s'", option);
1499 return (KORE_RESULT_ERROR);
1500 }
1501
1502 return (KORE_RESULT_OK);
1503 }
1504
1505 static int
1506 configure_http_body_disk_path(char *path)
1507 {
1508 if (strcmp(http_body_disk_path, HTTP_BODY_DISK_PATH))
1509 kore_free(http_body_disk_path);
1510
1511 http_body_disk_path = kore_strdup(path);
1512 return (KORE_RESULT_OK);
1513 }
1514
1515 static int
1516 configure_http_server_version(char *version)
1517 {
1518 http_server_version(version);
1519
1520 return (KORE_RESULT_OK);
1521 }
1522
1523 static int
1524 configure_http_pretty_error(char *yesno)
1525 {
1526 if (!strcmp(yesno, "no")) {
1527 http_pretty_error = 0;
1528 } else if (!strcmp(yesno, "yes")) {
1529 http_pretty_error = 1;
1530 } else {
1531 kore_log(LOG_ERR,
1532 "invalid '%s' for yes|no http_pretty_error option", yesno);
1533 return (KORE_RESULT_ERROR);
1534 }
1535
1536 return (KORE_RESULT_OK);
1537 }
1538
1539 static int
1540 configure_http_hsts_enable(char *option)
1541 {
1542 int err;
1543
1544 http_hsts_enable = kore_strtonum(option, 10, 0, LONG_MAX, &err);
1545 if (err != KORE_RESULT_OK) {
1546 kore_log(LOG_ERR, "bad http_hsts_enable value '%s'", option);
1547 return (KORE_RESULT_ERROR);
1548 }
1549
1550 return (KORE_RESULT_OK);
1551 }
1552
1553 static int
1554 configure_http_keepalive_time(char *option)
1555 {
1556 int err;
1557
1558 http_keepalive_time = kore_strtonum(option, 10, 0, USHRT_MAX, &err);
1559 if (err != KORE_RESULT_OK) {
1560 kore_log(LOG_ERR,
1561 "bad http_keepalive_time value '%s'", option);
1562 return (KORE_RESULT_ERROR);
1563 }
1564
1565 return (KORE_RESULT_OK);
1566 }
1567
1568 static int
1569 configure_http_request_ms(char *option)
1570 {
1571 int err;
1572
1573 http_request_ms = kore_strtonum(option, 10, 0, UINT_MAX, &err);
1574 if (err != KORE_RESULT_OK) {
1575 kore_log(LOG_ERR, "bad http_request_ms value '%s'", option);
1576 return (KORE_RESULT_ERROR);
1577 }
1578
1579 return (KORE_RESULT_OK);
1580 }
1581
1582 static int
1583 configure_http_request_limit(char *option)
1584 {
1585 int err;
1586
1587 http_request_limit = kore_strtonum(option, 10, 0, UINT_MAX, &err);
1588 if (err != KORE_RESULT_OK) {
1589 kore_log(LOG_ERR, "bad http_request_limit value '%s'", option);
1590 return (KORE_RESULT_ERROR);
1591 }
1592
1593 return (KORE_RESULT_OK);
1594 }
1595
1596 static int
1597 configure_validator(char *name)
1598 {
1599 u_int8_t type;
1600 char *tname, *value;
1601
1602 if ((tname = strchr(name, ' ')) == NULL) {
1603 kore_log(LOG_ERR, "missing validator name");
1604 return (KORE_RESULT_ERROR);
1605 }
1606
1607 *(tname)++ = '\0';
1608 tname = kore_text_trim(tname, strlen(tname));
1609 if ((value = strchr(tname, ' ')) == NULL) {
1610 kore_log(LOG_ERR, "missing validator value");
1611 return (KORE_RESULT_ERROR);
1612 }
1613
1614 *(value)++ = '\0';
1615 value = kore_text_trim(value, strlen(value));
1616
1617 if (!strcmp(tname, "regex")) {
1618 type = KORE_VALIDATOR_TYPE_REGEX;
1619 } else if (!strcmp(tname, "function")) {
1620 type = KORE_VALIDATOR_TYPE_FUNCTION;
1621 } else {
1622 kore_log(LOG_ERR,
1623 "bad type '%s' for validator '%s'", tname, name);
1624 return (KORE_RESULT_ERROR);
1625 }
1626
1627 if (!kore_validator_add(name, type, value)) {
1628 kore_log(LOG_ERR, "bad validator specified for '%s'", name);
1629 return (KORE_RESULT_ERROR);
1630 }
1631
1632 return (KORE_RESULT_OK);
1633 }
1634
1635 static int
1636 configure_validate(char *options)
1637 {
1638 struct kore_validator *val;
1639 struct kore_route_params *param;
1640 char *method, *argv[4];
1641 int flags, http_method;
1642
1643 if (kore_split_string(options, " ", argv, 4) != 3) {
1644 kore_log(LOG_ERR,
1645 "validate keyword needs 3 args: method param validator");
1646 return (KORE_RESULT_ERROR);
1647 }
1648
1649 flags = 0;
1650
1651 if ((method = strchr(argv[0], ':')) != NULL) {
1652 *(method)++ = '\0';
1653 if (!strcasecmp(argv[0], "qs")) {
1654 flags = KORE_PARAMS_QUERY_STRING;
1655 } else {
1656 kore_log(LOG_ERR,
1657 "unknown validate method prefix '%s' for '%s'",
1658 argv[0], current_route->path);
1659 return (KORE_RESULT_ERROR);
1660 }
1661 } else {
1662 method = argv[0];
1663 }
1664
1665 if ((val = kore_validator_lookup(argv[2])) == NULL) {
1666 kore_log(LOG_ERR, "unknown validator '%s'", argv[2]);
1667 return (KORE_RESULT_ERROR);
1668 }
1669
1670 if (!strcasecmp(method, "post")) {
1671 http_method = HTTP_METHOD_POST;
1672 } else if (!strcasecmp(method, "get")) {
1673 http_method = HTTP_METHOD_GET;
1674 /* Let params get /foo {} imply qs:get automatically. */
1675 flags |= KORE_PARAMS_QUERY_STRING;
1676 } else if (!strcasecmp(method, "put")) {
1677 http_method = HTTP_METHOD_PUT;
1678 } else if (!strcasecmp(method, "delete")) {
1679 http_method = HTTP_METHOD_DELETE;
1680 } else if (!strcasecmp(method, "head")) {
1681 http_method = HTTP_METHOD_HEAD;
1682 } else if (!strcasecmp(method, "patch")) {
1683 http_method = HTTP_METHOD_PATCH;
1684 } else {
1685 kore_log(LOG_ERR, "unknown method: %s in validator for %s",
1686 method, current_route->path);
1687 return (KORE_RESULT_ERROR);
1688 }
1689
1690 if (!(current_route->methods & http_method)) {
1691 kore_log(LOG_ERR, "method '%s' not enabled for route '%s'",
1692 method, current_route->path);
1693 return (KORE_RESULT_ERROR);
1694 }
1695
1696 param = kore_calloc(1, sizeof(*param));
1697
1698 param->flags = flags;
1699 param->validator = val;
1700 param->method = http_method;
1701 param->name = kore_strdup(argv[1]);
1702
1703 TAILQ_INSERT_TAIL(¤t_route->params, param, list);
1704
1705 return (KORE_RESULT_OK);
1706 }
1707
1708 static int
1709 configure_authentication(char *options)
1710 {
1711 char *argv[3];
1712
1713 if (current_auth != NULL) {
1714 kore_log(LOG_ERR, "previous authentication block not closed");
1715 return (KORE_RESULT_ERROR);
1716 }
1717
1718 kore_split_string(options, " ", argv, 3);
1719 if (argv[1] == NULL) {
1720 kore_log(LOG_ERR, "missing name for authentication block");
1721 return (KORE_RESULT_ERROR);
1722 }
1723
1724 if (strcmp(argv[1], "{")) {
1725 kore_log(LOG_ERR, "missing { for authentication block");
1726 return (KORE_RESULT_ERROR);
1727 }
1728
1729 if (!kore_auth_new(argv[0]))
1730 return (KORE_RESULT_ERROR);
1731
1732 current_auth = kore_auth_lookup(argv[0]);
1733
1734 return (KORE_RESULT_OK);
1735 }
1736
1737 static int
1738 configure_authentication_type(char *option)
1739 {
1740 if (current_auth == NULL) {
1741 kore_log(LOG_ERR,
1742 "authentication_type keyword not in correct context");
1743 return (KORE_RESULT_ERROR);
1744 }
1745
1746 if (!strcmp(option, "cookie")) {
1747 current_auth->type = KORE_AUTH_TYPE_COOKIE;
1748 } else if (!strcmp(option, "header")) {
1749 current_auth->type = KORE_AUTH_TYPE_HEADER;
1750 } else if (!strcmp(option, "request")) {
1751 current_auth->type = KORE_AUTH_TYPE_REQUEST;
1752 } else {
1753 kore_log(LOG_ERR, "unknown authentication type '%s'", option);
1754 return (KORE_RESULT_ERROR);
1755 }
1756
1757 return (KORE_RESULT_OK);
1758 }
1759
1760 static int
1761 configure_authentication_value(char *option)
1762 {
1763 if (current_auth == NULL) {
1764 kore_log(LOG_ERR,
1765 "authentication_value keyword not in correct context");
1766 return (KORE_RESULT_ERROR);
1767 }
1768
1769 if (current_auth->value != NULL)
1770 kore_free(current_auth->value);
1771 current_auth->value = kore_strdup(option);
1772
1773 return (KORE_RESULT_OK);
1774 }
1775
1776 static int
1777 configure_authentication_validator(char *validator)
1778 {
1779 struct kore_validator *val;
1780
1781 if (current_auth == NULL) {
1782 kore_log(LOG_ERR,
1783 "authentication_validator not in correct context");
1784 return (KORE_RESULT_ERROR);
1785 }
1786
1787 if ((val = kore_validator_lookup(validator)) == NULL) {
1788 kore_log(LOG_ERR,
1789 "authentication validator '%s' not found", validator);
1790 return (KORE_RESULT_ERROR);
1791 }
1792
1793 current_auth->validator = val;
1794
1795 return (KORE_RESULT_OK);
1796 }
1797
1798 static int
1799 configure_authentication_uri(char *uri)
1800 {
1801 if (current_auth == NULL) {
1802 kore_log(LOG_ERR,
1803 "authentication_uri keyword not in correct context");
1804 return (KORE_RESULT_ERROR);
1805 }
1806
1807 if (current_auth->redirect != NULL)
1808 kore_free(current_auth->redirect);
1809 current_auth->redirect = kore_strdup(uri);
1810
1811 return (KORE_RESULT_OK);
1812 }
1813
1814 static int
1815 configure_websocket_maxframe(char *option)
1816 {
1817 int err;
1818
1819 kore_websocket_maxframe = kore_strtonum64(option, 1, &err);
1820 if (err != KORE_RESULT_OK) {
1821 kore_log(LOG_ERR,
1822 "bad kore_websocket_maxframe value '%s'", option);
1823 return (KORE_RESULT_ERROR);
1824 }
1825
1826 return (KORE_RESULT_OK);
1827 }
1828
1829 static int
1830 configure_websocket_timeout(char *option)
1831 {
1832 int err;
1833
1834 kore_websocket_timeout = kore_strtonum64(option, 1, &err);
1835 if (err != KORE_RESULT_OK) {
1836 kore_log(LOG_ERR,
1837 "bad kore_websocket_timeout value '%s'", option);
1838 return (KORE_RESULT_ERROR);
1839 }
1840
1841 kore_websocket_timeout = kore_websocket_timeout * 1000;
1842
1843 return (KORE_RESULT_OK);
1844 }
1845
1846 #endif /* !KORE_NO_HTTP */
1847
1848 static int
1849 configure_logfile(char *path)
1850 {
1851 kore_log_file(path);
1852 return (KORE_RESULT_OK);
1853 }
1854
1855 static int
1856 configure_workers(char *option)
1857 {
1858 int err;
1859
1860 worker_count = kore_strtonum(option, 10, 1, KORE_WORKER_MAX, &err);
1861 if (err != KORE_RESULT_OK) {
1862 kore_log(LOG_ERR, "bad value for worker '%s'", option);
1863 return (KORE_RESULT_ERROR);
1864 }
1865
1866 return (KORE_RESULT_OK);
1867 }
1868
1869 static int
1870 configure_pidfile(char *path)
1871 {
1872 if (strcmp(kore_pidfile, KORE_PIDFILE_DEFAULT))
1873 kore_free(kore_pidfile);
1874 kore_pidfile = kore_strdup(path);
1875
1876 return (KORE_RESULT_OK);
1877 }
1878
1879 static int
1880 configure_max_connections(char *option)
1881 {
1882 int err;
1883
1884 worker_max_connections = kore_strtonum(option, 10, 1, UINT_MAX, &err);
1885 if (err != KORE_RESULT_OK) {
1886 kore_log(LOG_ERR,
1887 "bad value for worker_max_connections '%s'", option);
1888 return (KORE_RESULT_ERROR);
1889 }
1890
1891 return (KORE_RESULT_OK);
1892 }
1893
1894 static int
1895 configure_rlimit_nofiles(char *option)
1896 {
1897 int err;
1898
1899 worker_rlimit_nofiles = kore_strtonum(option, 10, 1, UINT_MAX, &err);
1900 if (err != KORE_RESULT_OK) {
1901 kore_log(LOG_ERR,
1902 "bad value for worker_rlimit_nofiles '%s'", option);
1903 return (KORE_RESULT_ERROR);
1904 }
1905
1906 return (KORE_RESULT_OK);
1907 }
1908
1909 static int
1910 configure_accept_threshold(char *option)
1911 {
1912 int err;
1913
1914 worker_accept_threshold = kore_strtonum(option, 0, 1, UINT_MAX, &err);
1915 if (err != KORE_RESULT_OK) {
1916 kore_log(LOG_ERR,
1917 "bad value for worker_accept_threshold '%s'\n", option);
1918 return (KORE_RESULT_ERROR);
1919 }
1920
1921 return (KORE_RESULT_OK);
1922 }
1923
1924 static int
1925 configure_death_policy(char *option)
1926 {
1927 if (!strcmp(option, "restart")) {
1928 worker_policy = KORE_WORKER_POLICY_RESTART;
1929 } else if (!strcmp(option, "terminate")) {
1930 worker_policy = KORE_WORKER_POLICY_TERMINATE;
1931 } else {
1932 kore_log(LOG_ERR,
1933 "bad value for worker_death_policy '%s'\n", option);
1934 return (KORE_RESULT_ERROR);
1935 }
1936
1937 return (KORE_RESULT_OK);
1938 }
1939
1940 static int
1941 configure_set_affinity(char *option)
1942 {
1943 int err;
1944
1945 worker_set_affinity = kore_strtonum(option, 10, 0, 1, &err);
1946 if (err != KORE_RESULT_OK) {
1947 kore_log(LOG_ERR,
1948 "bad value for worker_set_affinity '%s'", option);
1949 return (KORE_RESULT_ERROR);
1950 }
1951
1952 return (KORE_RESULT_OK);
1953 }
1954
1955 static int
1956 configure_socket_backlog(char *option)
1957 {
1958 int err;
1959
1960 kore_socket_backlog = kore_strtonum(option, 10, 0, UINT_MAX, &err);
1961 if (err != KORE_RESULT_OK) {
1962 kore_log(LOG_ERR, "bad socket_backlog value: '%s'", option);
1963 return (KORE_RESULT_ERROR);
1964 }
1965
1966 return (KORE_RESULT_OK);
1967 }
1968
1969 #if defined(KORE_USE_PGSQL)
1970 static int
1971 configure_pgsql_conn_max(char *option)
1972 {
1973 int err;
1974
1975 pgsql_conn_max = kore_strtonum(option, 10, 0, USHRT_MAX, &err);
1976 if (err != KORE_RESULT_OK) {
1977 kore_log(LOG_ERR, "bad value for pgsql_conn_max '%s'", option);
1978 return (KORE_RESULT_ERROR);
1979 }
1980
1981 return (KORE_RESULT_OK);
1982 }
1983
1984 static int
1985 configure_pgsql_queue_limit(char *option)
1986 {
1987 int err;
1988
1989 pgsql_queue_limit = kore_strtonum(option, 10, 0, UINT_MAX, &err);
1990 if (err != KORE_RESULT_OK) {
1991 kore_log(LOG_ERR,
1992 "bad value for pgsql_queue_limit '%s'", option);
1993 return (KORE_RESULT_ERROR);
1994 }
1995
1996 return (KORE_RESULT_OK);
1997 }
1998 #endif
1999
2000 #if defined(KORE_USE_TASKS)
2001 static int
2002 configure_task_threads(char *option)
2003 {
2004 int err;
2005
2006 kore_task_threads = kore_strtonum(option, 10, 0, UCHAR_MAX, &err);
2007 if (err != KORE_RESULT_OK) {
2008 kore_log(LOG_ERR, "bad value for task_threads: '%s'", option);
2009 return (KORE_RESULT_ERROR);
2010 }
2011
2012 return (KORE_RESULT_OK);
2013 }
2014 #endif
2015
2016 static int
2017 configure_deployment(char *value)
2018 {
2019 if (!strcmp(value, "docker")) {
2020 kore_foreground = 1;
2021 skip_runas = 0;
2022 skip_chroot = 0;
2023 } else if (!strcmp(value, "dev") || !strcmp(value, "development")) {
2024 kore_foreground = 1;
2025 skip_runas = 1;
2026 skip_chroot = 1;
2027 } else if (!strcmp(value, "production")) {
2028 kore_foreground = 0;
2029 skip_runas = 0;
2030 skip_chroot = 0;
2031 } else {
2032 kore_log(LOG_NOTICE,
2033 "kore.config.deployment: bad value '%s'", value);
2034 return (KORE_RESULT_ERROR);
2035 }
2036
2037 return (KORE_RESULT_OK);
2038 }
2039
2040 #if defined(KORE_USE_PYTHON)
2041 static int
2042 configure_python_path(char *path)
2043 {
2044 kore_python_path(path);
2045
2046 return (KORE_RESULT_OK);
2047 }
2048
2049 static int
2050 configure_python_import(char *module)
2051 {
2052 char *argv[3];
2053
2054 kore_split_string(module, " ", argv, 3);
2055 if (argv[0] == NULL)
2056 return (KORE_RESULT_ERROR);
2057
2058 kore_module_load(argv[0], argv[1], KORE_MODULE_PYTHON);
2059 return (KORE_RESULT_OK);
2060 }
2061 #endif
2062
2063 #if defined(KORE_USE_PLATFORM_PLEDGE)
2064 static int
2065 configure_add_pledge(char *pledge)
2066 {
2067 kore_platform_add_pledge(pledge);
2068
2069 return (KORE_RESULT_OK);
2070 }
2071 #endif
2072
2073 #if defined(KORE_USE_CURL)
2074 static int
2075 configure_curl_recv_max(char *option)
2076 {
2077 int err;
2078
2079 kore_curl_recv_max = kore_strtonum64(option, 1, &err);
2080 if (err != KORE_RESULT_OK) {
2081 kore_log(LOG_ERR, "bad curl_recv_max value '%s'\n", option);
2082 return (KORE_RESULT_ERROR);
2083 }
2084
2085 return (KORE_RESULT_OK);
2086 }
2087
2088 static int
2089 configure_curl_timeout(char *option)
2090 {
2091 int err;
2092
2093 kore_curl_timeout = kore_strtonum(option, 10, 0, USHRT_MAX, &err);
2094 if (err != KORE_RESULT_OK) {
2095 kore_log(LOG_ERR, "bad kore_curl_timeout value: '%s'", option);
2096 return (KORE_RESULT_ERROR);
2097 }
2098
2099 return (KORE_RESULT_OK);
2100 }
2101 #endif
2102
2103 #if defined(__linux__)
2104 static int
2105 configure_seccomp_tracing(char *opt)
2106 {
2107 if (!strcmp(opt, "yes")) {
2108 kore_seccomp_tracing = 1;
2109 } else if (!strcmp(opt, "no")) {
2110 kore_seccomp_tracing = 0;
2111 } else {
2112 kore_log(LOG_ERR,
2113 "bad seccomp_tracing value '%s' (expected yes|no)\n", opt);
2114 return (KORE_RESULT_ERROR);
2115 }
2116
2117 return (KORE_RESULT_OK);
2118 }
2119 #endif