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