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