config.c (49271B)
1 /*
2 * Copyright (c) 2013-2022 Joris Vink <joris@coders.se>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include <sys/param.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdint.h>
24 #include <ctype.h>
25 #include <limits.h>
26 #include <fcntl.h>
27 #include <pwd.h>
28
29 #include "kore.h"
30 #include "http.h"
31
32 #if defined(KORE_USE_PGSQL)
33 #include "pgsql.h"
34 #endif
35
36 #if defined(KORE_USE_TASKS)
37 #include "tasks.h"
38 #endif
39
40 #if defined(KORE_USE_PYTHON)
41 #include "python_api.h"
42 #endif
43
44 #if defined(KORE_USE_CURL)
45 #include "curl.h"
46 #endif
47
48 #if defined(KORE_USE_ACME)
49 #include "acme.h"
50 #endif
51
52 #if defined(__linux__)
53 #include "seccomp.h"
54 #endif
55
56 /* XXX - This is becoming a clusterfuck. Fix it. */
57
58 static int configure_load(char *);
59 static char *configure_resolve_var(char *);
60 static void configure_check_var(char **, const char *, const char *);
61
62 #if defined(KORE_SINGLE_BINARY)
63 static FILE *config_file_write(void);
64 extern u_int8_t asset_builtin_kore_conf[];
65 extern u_int32_t asset_len_builtin_kore_conf;
66 #elif defined(KORE_USE_PYTHON)
67 static int configure_file(char *);
68 #endif
69
70 #if defined(KORE_USE_ACME)
71 static int configure_acme(char *);
72 static int configure_acme_email(char *);
73 static int configure_acme_provider(char *);
74 #endif
75
76 static int configure_tls(char *);
77 static int configure_server(char *);
78 static int configure_include(char *);
79 static int configure_bind(char *);
80 static int configure_bind_unix(char *);
81 static int configure_attach(char *);
82 static int configure_domain(char *);
83 static int configure_privsep(char *);
84 static int configure_logfile(char *);
85 static int configure_workers(char *);
86 static int configure_pidfile(char *);
87 static int configure_rlimit_nofiles(char *);
88 static int configure_max_connections(char *);
89 static int configure_accept_threshold(char *);
90 static int configure_death_policy(char *);
91 static int configure_set_affinity(char *);
92 static int configure_socket_backlog(char *);
93 static int configure_privsep_skip(char *);
94 static int configure_privsep_root(char *);
95 static int configure_privsep_runas(char *);
96
97 #if defined(KORE_USE_PLATFORM_PLEDGE)
98 static int configure_add_pledge(char *);
99 #endif
100
101 static int configure_rand_file(char *);
102 static int configure_certfile(char *);
103 static int configure_certkey(char *);
104 static int configure_tls_version(char *);
105 static int configure_tls_cipher(char *);
106 static int configure_tls_dhparam(char *);
107 static int configure_client_verify(char *);
108 static int configure_client_verify_depth(char *);
109
110 #if !defined(KORE_NO_HTTP)
111 static int configure_route(char *);
112 static int configure_route_methods(char *);
113 static int configure_route_handler(char *);
114 static int configure_route_on_free(char *);
115 static int configure_route_on_headers(char *);
116 static int configure_route_authenticate(char *);
117 static int configure_route_on_body_chunk(char *);
118 static int configure_filemap(char *);
119 static int configure_return(char *);
120 static int configure_redirect(char *);
121 static int configure_static_handler(char *);
122 static int configure_dynamic_handler(char *);
123 static int configure_accesslog(char *);
124 static int configure_http_header_max(char *);
125 static int configure_http_header_timeout(char *);
126 static int configure_http_body_max(char *);
127 static int configure_http_body_timeout(char *);
128 static int configure_filemap_ext(char *);
129 static int configure_filemap_index(char *);
130 static int configure_http_media_type(char *);
131 static int configure_http_hsts_enable(char *);
132 static int configure_http_keepalive_time(char *);
133 static int configure_http_request_ms(char *);
134 static int configure_http_request_limit(char *);
135 static int configure_http_body_disk_offload(char *);
136 static int configure_http_body_disk_path(char *);
137 static int configure_http_server_version(char *);
138 static int configure_http_pretty_error(char *);
139 static int configure_validator(char *);
140 static int configure_validate(char *);
141 static int configure_authentication(char *);
142 static int configure_authentication_uri(char *);
143 static int configure_authentication_type(char *);
144 static int configure_authentication_value(char *);
145 static int configure_authentication_validator(char *);
146 static int configure_websocket_maxframe(char *);
147 static int configure_websocket_timeout(char *);
148 #endif
149
150 #if defined(KORE_USE_PGSQL)
151 static int configure_pgsql_conn_max(char *);
152 static int configure_pgsql_queue_limit(char *);
153 #endif
154
155 #if defined(KORE_USE_TASKS)
156 static int configure_task_threads(char *);
157 #endif
158
159 #if defined(KORE_USE_PYTHON)
160 static int configure_deployment(char *);
161 static int configure_python_path(char *);
162 static int configure_python_import(char *);
163 #endif
164
165 #if defined(KORE_USE_CURL)
166 static int configure_curl_timeout(char *);
167 static int configure_curl_recv_max(char *);
168 #endif
169
170 #if defined(__linux__)
171 static int configure_seccomp_tracing(char *);
172 #endif
173
174 static struct {
175 const char *name;
176 int (*configure)(char *);
177 } config_directives[] = {
178 { "tls", configure_tls },
179 #if defined(KORE_USE_ACME)
180 { "acme", configure_acme },
181 #endif
182 { "bind", configure_bind },
183 { "load", configure_load },
184 { "domain", configure_domain },
185 { "privsep", configure_privsep },
186 { "server", configure_server },
187 { "attach", configure_attach },
188 { "certkey", configure_certkey },
189 { "certfile", configure_certfile },
190 { "include", configure_include },
191 { "unix", configure_bind_unix },
192 { "skip", configure_privsep_skip },
193 { "root", configure_privsep_root },
194 { "runas", configure_privsep_runas },
195 { "client_verify", configure_client_verify },
196 { "client_verify_depth", configure_client_verify_depth },
197 #if defined(KORE_USE_PYTHON)
198 { "python_path", configure_python_path },
199 { "python_import", configure_python_import },
200 #endif
201 #if !defined(KORE_NO_HTTP)
202 { "route", configure_route },
203 { "handler", configure_route_handler },
204 { "on_headers", configure_route_on_headers },
205 { "on_body_chunk", configure_route_on_body_chunk },
206 { "on_free", configure_route_on_free },
207 { "methods", configure_route_methods },
208 { "authenticate", configure_route_authenticate },
209 { "filemap", configure_filemap },
210 { "redirect", configure_redirect },
211 { "return", configure_return },
212 { "static", configure_static_handler },
213 { "dynamic", configure_dynamic_handler },
214 { "accesslog", configure_accesslog },
215 { "validator", configure_validator },
216 { "validate", configure_validate },
217 { "authentication", configure_authentication },
218 { "authentication_uri", configure_authentication_uri },
219 { "authentication_type", configure_authentication_type },
220 { "authentication_value", configure_authentication_value },
221 { "authentication_validator", configure_authentication_validator },
222 #endif
223 { NULL, NULL },
224 };
225
226 static struct {
227 const char *name;
228 int (*configure)(char *);
229 } config_settings[] = {
230 { "logfile", configure_logfile },
231 { "workers", configure_workers },
232 { "worker_max_connections", configure_max_connections },
233 { "worker_rlimit_nofiles", configure_rlimit_nofiles },
234 { "worker_accept_threshold", configure_accept_threshold },
235 { "worker_death_policy", configure_death_policy },
236 { "worker_set_affinity", configure_set_affinity },
237 { "pidfile", configure_pidfile },
238 { "socket_backlog", configure_socket_backlog },
239 { "tls_version", configure_tls_version },
240 { "tls_cipher", configure_tls_cipher },
241 { "tls_dhparam", configure_tls_dhparam },
242 { "rand_file", configure_rand_file },
243 #if defined(KORE_USE_ACME)
244 { "acme_email", configure_acme_email },
245 { "acme_provider", configure_acme_provider },
246 #endif
247 #if defined(KORE_USE_PLATFORM_PLEDGE)
248 { "pledge", configure_add_pledge },
249 #endif
250 #if defined(__linux__)
251 { "seccomp_tracing", configure_seccomp_tracing },
252 #endif
253 #if !defined(KORE_NO_HTTP)
254 { "filemap_ext", configure_filemap_ext },
255 { "filemap_index", configure_filemap_index },
256 { "http_media_type", configure_http_media_type },
257 { "http_header_max", configure_http_header_max },
258 { "http_header_timeout", configure_http_header_timeout },
259 { "http_body_max", configure_http_body_max },
260 { "http_body_timeout", configure_http_body_timeout },
261 { "http_hsts_enable", configure_http_hsts_enable },
262 { "http_keepalive_time", configure_http_keepalive_time },
263 { "http_request_ms", configure_http_request_ms },
264 { "http_request_limit", configure_http_request_limit },
265 { "http_body_disk_offload", configure_http_body_disk_offload },
266 { "http_body_disk_path", configure_http_body_disk_path },
267 { "http_server_version", configure_http_server_version },
268 { "http_pretty_error", configure_http_pretty_error },
269 { "websocket_maxframe", configure_websocket_maxframe },
270 { "websocket_timeout", configure_websocket_timeout },
271 #endif
272 #if defined(KORE_USE_PYTHON)
273 { "deployment", configure_deployment },
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 #if defined(KORE_USE_PYTHON)
528 int
529 kore_configure_setting(const char *name, char *value)
530 {
531 int i;
532
533 if (finalized)
534 return (KORE_RESULT_ERROR);
535
536 for (i = 0; config_settings[i].name != NULL; i++) {
537 if (!strcmp(config_settings[i].name, name)) {
538 if (config_settings[i].configure(value))
539 return (KORE_RESULT_OK);
540 fatal("bad value '%s' for '%s'", value, name);
541 }
542 }
543
544 kore_log(LOG_NOTICE, "ignoring unknown kore.config.%s setting", name);
545 return (KORE_RESULT_OK);
546 }
547 #endif
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), "/tmp/%s.XXXXXX", __progname);
765 if (len == -1 || (size_t)len >= sizeof(fpath))
766 fatal("failed to create temporary path");
767
768 if ((fd = mkstemp(fpath)) == -1)
769 fatal("mkstemp(%s): %s", fpath, errno_s);
770
771 (void)unlink(fpath);
772
773 for (;;) {
774 ret = write(fd, asset_builtin_kore_conf,
775 asset_len_builtin_kore_conf);
776 if (ret == -1) {
777 if (errno == EINTR)
778 continue;
779 fatal("failed to write temporary config: %s", errno_s);
780 }
781
782 if ((size_t)ret != asset_len_builtin_kore_conf)
783 fatal("failed to write temporary config");
784 break;
785 }
786
787 if ((fp = fdopen(fd, "w+")) == NULL)
788 fatal("fdopen(): %s", errno_s);
789
790 rewind(fp);
791
792 return (fp);
793 }
794 #elif defined(KORE_USE_PYTHON)
795 static int
796 configure_file(char *file)
797 {
798 free(config_file);
799 if ((config_file = strdup(file)) == NULL)
800 fatal("strdup");
801
802 return (KORE_RESULT_OK);
803 }
804 #endif
805
806 static int
807 configure_tls_version(char *version)
808 {
809 int ver;
810
811 if (!strcmp(version, "1.3")) {
812 ver = KORE_TLS_VERSION_1_3;
813 } else if (!strcmp(version, "1.2")) {
814 ver = KORE_TLS_VERSION_1_2;
815 } else if (!strcmp(version, "both")) {
816 ver = KORE_TLS_VERSION_BOTH;
817 } else {
818 kore_log(LOG_ERR,
819 "unknown value for tls_version: %s (use 1.3, 1.2, both)",
820 version);
821 return (KORE_RESULT_ERROR);
822 }
823
824 kore_tls_version_set(ver);
825
826 return (KORE_RESULT_OK);
827 }
828
829 static int
830 configure_tls_cipher(char *cipherlist)
831 {
832 return (kore_tls_ciphersuite_set(cipherlist));
833 }
834
835 static int
836 configure_tls_dhparam(char *path)
837 {
838 return (kore_tls_dh_load(path));
839 }
840
841 static int
842 configure_client_verify_depth(char *value)
843 {
844 int err, depth;
845
846 if (current_domain == NULL) {
847 kore_log(LOG_ERR,
848 "client_verify_depth keyword not in domain context");
849 return (KORE_RESULT_ERROR);
850 }
851
852 depth = kore_strtonum(value, 10, 0, INT_MAX, &err);
853 if (err != KORE_RESULT_OK) {
854 kore_log(LOG_ERR, "bad client_verify_depth value: %s", value);
855 return (KORE_RESULT_ERROR);
856 }
857
858 current_domain->x509_verify_depth = depth;
859
860 return (KORE_RESULT_OK);
861 }
862
863 static int
864 configure_client_verify(char *options)
865 {
866 char *argv[3];
867
868 if (current_domain == NULL) {
869 kore_log(LOG_ERR,
870 "client_verify keyword not in domain context");
871 return (KORE_RESULT_ERROR);
872 }
873
874 kore_split_string(options, " ", argv, 3);
875 if (argv[0] == NULL) {
876 kore_log(LOG_ERR, "client_verify is missing a parameter");
877 return (KORE_RESULT_ERROR);
878 }
879
880 if (current_domain->cafile != NULL) {
881 kore_log(LOG_ERR, "client_verify already set for '%s'",
882 current_domain->domain);
883 return (KORE_RESULT_ERROR);
884 }
885
886 current_domain->cafile = kore_strdup(argv[0]);
887 if (argv[1] != NULL)
888 current_domain->crlfile = kore_strdup(argv[1]);
889
890 return (KORE_RESULT_OK);
891 }
892
893 static int
894 configure_rand_file(char *path)
895 {
896 if (kore_rand_file != NULL)
897 kore_free(kore_rand_file);
898
899 kore_rand_file = kore_strdup(path);
900
901 return (KORE_RESULT_OK);
902 }
903
904 static int
905 configure_certfile(char *path)
906 {
907 if (current_domain == NULL) {
908 kore_log(LOG_ERR,
909 "certfile keyword not specified in domain context");
910 return (KORE_RESULT_ERROR);
911 }
912
913 kore_free(current_domain->certfile);
914 current_domain->certfile = kore_strdup(path);
915 return (KORE_RESULT_OK);
916 }
917
918 static int
919 configure_certkey(char *path)
920 {
921 if (current_domain == NULL) {
922 kore_log(LOG_ERR,
923 "certkey keyword not specified in domain context");
924 return (KORE_RESULT_ERROR);
925 }
926
927 kore_free(current_domain->certkey);
928 current_domain->certkey = kore_strdup(path);
929 return (KORE_RESULT_OK);
930 }
931
932 static int
933 configure_privsep(char *options)
934 {
935 char *argv[3];
936
937 if (current_privsep != NULL) {
938 kore_log(LOG_ERR, "nested privsep contexts are not allowed");
939 return (KORE_RESULT_ERROR);
940 }
941
942 kore_split_string(options, " ", argv, 3);
943
944 if (argv[0] == NULL || argv[1] == NULL) {
945 kore_log(LOG_ERR, "invalid privsep context");
946 return (KORE_RESULT_ERROR);
947 }
948
949 if (strcmp(argv[1], "{")) {
950 kore_log(LOG_ERR, "privsep context not opened correctly");
951 return (KORE_RESULT_ERROR);
952 }
953
954 if (!strcmp(argv[0], "worker")) {
955 current_privsep = &worker_privsep;
956 } else if (!strcmp(argv[0], "keymgr")) {
957 current_privsep = &keymgr_privsep;
958 #if defined(KORE_USE_ACME)
959 } else if (!strcmp(argv[0], "acme")) {
960 current_privsep = &acme_privsep;
961 #endif
962 } else {
963 kore_log(LOG_ERR, "unknown privsep context: %s", argv[0]);
964 return (KORE_RESULT_ERROR);
965 }
966
967 return (KORE_RESULT_OK);
968 }
969
970 static int
971 configure_privsep_runas(char *user)
972 {
973 if (current_privsep == NULL) {
974 kore_log(LOG_ERR, "runas keyword not in privsep context");
975 return (KORE_RESULT_ERROR);
976 }
977
978 if (current_privsep->runas != NULL)
979 kore_free(current_privsep->runas);
980
981 current_privsep->runas = kore_strdup(user);
982
983 return (KORE_RESULT_OK);
984 }
985
986 static int
987 configure_privsep_root(char *root)
988 {
989 if (current_privsep == NULL) {
990 kore_log(LOG_ERR, "root keyword not in privsep context");
991 return (KORE_RESULT_ERROR);
992 }
993
994 if (current_privsep->root != NULL)
995 kore_free(current_privsep->root);
996
997 current_privsep->root = kore_strdup(root);
998
999 return (KORE_RESULT_OK);
1000 }
1001
1002 static int
1003 configure_privsep_skip(char *option)
1004 {
1005 if (current_privsep == NULL) {
1006 kore_log(LOG_ERR, "skip keyword not in privsep context");
1007 return (KORE_RESULT_ERROR);
1008 }
1009
1010 if (!strcmp(option, "chroot")) {
1011 current_privsep->skip_chroot = 1;
1012 } else {
1013 kore_log(LOG_ERR, "unknown skip option '%s'", option);
1014 return (KORE_RESULT_ERROR);
1015 }
1016
1017 return (KORE_RESULT_OK);
1018 }
1019
1020 static int
1021 configure_domain(char *options)
1022 {
1023 char *argv[3];
1024
1025 if (current_domain != NULL) {
1026 kore_log(LOG_ERR, "nested domain contexts are not allowed");
1027 return (KORE_RESULT_ERROR);
1028 }
1029
1030 kore_split_string(options, " ", argv, 3);
1031
1032 if (argv[0] == NULL || argv[1] == NULL) {
1033 kore_log(LOG_ERR, "invalid domain context");
1034 return (KORE_RESULT_ERROR);
1035 }
1036
1037 if (strcmp(argv[1], "{")) {
1038 kore_log(LOG_ERR, "domain context not opened correctly");
1039 return (KORE_RESULT_ERROR);
1040 }
1041
1042 if (strlen(argv[0]) >= KORE_DOMAINNAME_LEN - 1) {
1043 kore_log(LOG_ERR, "domain name '%s' too long", argv[0]);
1044 return (KORE_RESULT_ERROR);
1045 }
1046
1047 current_domain = kore_domain_new(argv[0]);
1048
1049 return (KORE_RESULT_OK);
1050 }
1051
1052 static int
1053 configure_attach(char *name)
1054 {
1055 struct kore_server *srv;
1056
1057 if (current_domain == NULL) {
1058 kore_log(LOG_ERR, "attach keyword not in domain context");
1059 return (KORE_RESULT_ERROR);
1060 }
1061
1062 if (current_domain->server != NULL) {
1063 kore_log(LOG_ERR, "domain '%s' already attached to server",
1064 current_domain->domain);
1065 return (KORE_RESULT_ERROR);
1066 }
1067
1068 if ((srv = kore_server_lookup(name)) == NULL) {
1069 kore_log(LOG_ERR, "server '%s' does not exist", name);
1070 return (KORE_RESULT_ERROR);
1071 }
1072
1073 if (!kore_domain_attach(current_domain, srv)) {
1074 kore_log(LOG_ERR, "failed to attach '%s' to '%s'",
1075 current_domain->domain, name);
1076 return (KORE_RESULT_ERROR);
1077 }
1078
1079 return (KORE_RESULT_OK);
1080 }
1081
1082 #if !defined(KORE_NO_HTTP)
1083 static int
1084 configure_static_handler(char *options)
1085 {
1086 kore_log(LOG_NOTICE, "static keyword removed, use route instead");
1087 return (KORE_RESULT_ERROR);
1088 }
1089
1090 static int
1091 configure_dynamic_handler(char *options)
1092 {
1093 kore_log(LOG_NOTICE, "dynamic keyword removed, use route instead");
1094 return (KORE_RESULT_ERROR);
1095 }
1096
1097 static int
1098 configure_route(char *options)
1099 {
1100 struct kore_route *rt;
1101 int type;
1102 char *argv[4];
1103
1104 if (current_domain == NULL) {
1105 kore_log(LOG_ERR, "route keyword not in domain context");
1106 return (KORE_RESULT_ERROR);
1107 }
1108
1109 if (current_route != NULL) {
1110 kore_log(LOG_ERR, "nested route contexts not allowed");
1111 return (KORE_RESULT_ERROR);
1112 }
1113
1114 kore_split_string(options, " ", argv, 4);
1115
1116 if (argv[1] == NULL || strcmp(argv[1], "{")) {
1117 kore_log(LOG_ERR, "invalid route context");
1118 return (KORE_RESULT_ERROR);
1119 }
1120
1121 if (*argv[0] == '/')
1122 type = HANDLER_TYPE_STATIC;
1123 else
1124 type = HANDLER_TYPE_DYNAMIC;
1125
1126 if ((rt = kore_route_create(current_domain, argv[0], type)) == NULL) {
1127 kore_log(LOG_ERR,
1128 "failed to create route handler for '%s'", argv[0]);
1129 return (KORE_RESULT_ERROR);
1130 }
1131
1132 current_route = rt;
1133
1134 return (KORE_RESULT_OK);
1135 }
1136
1137 static int
1138 configure_route_handler(char *name)
1139 {
1140 if (current_route == NULL) {
1141 kore_log(LOG_ERR,
1142 "handler keyword not inside of route context");
1143 return (KORE_RESULT_ERROR);
1144 }
1145
1146 kore_route_callback(current_route, name);
1147
1148 return (KORE_RESULT_OK);
1149 }
1150
1151 static int
1152 configure_route_on_headers(char *name)
1153 {
1154 if (current_route == NULL) {
1155 kore_log(LOG_ERR,
1156 "on_header keyword not inside of route context");
1157 return (KORE_RESULT_ERROR);
1158 }
1159
1160 if ((current_route->on_headers = kore_runtime_getcall(name)) == NULL) {
1161 kore_log(LOG_ERR, "on_headers callback '%s' for '%s' not found",
1162 name, current_route->path);
1163 return (KORE_RESULT_ERROR);
1164 }
1165
1166 return (KORE_RESULT_OK);
1167 }
1168
1169 static int
1170 configure_route_on_body_chunk(char *name)
1171 {
1172 if (current_route == NULL) {
1173 kore_log(LOG_ERR,
1174 "on_body_chunk keyword not inside of route context");
1175 return (KORE_RESULT_ERROR);
1176 }
1177
1178 current_route->on_body_chunk = kore_runtime_getcall(name);
1179 if (current_route->on_body_chunk == NULL) {
1180 kore_log(LOG_ERR,
1181 "on_body_chunk callback '%s' for '%s' not found",
1182 name, current_route->path);
1183 return (KORE_RESULT_ERROR);
1184 }
1185
1186 return (KORE_RESULT_OK);
1187 }
1188
1189 static int
1190 configure_route_on_free(char *name)
1191 {
1192 if (current_route == NULL) {
1193 kore_log(LOG_ERR,
1194 "on_free keyword not inside of route context");
1195 return (KORE_RESULT_ERROR);
1196 }
1197
1198 if ((current_route->on_free = kore_runtime_getcall(name)) == NULL) {
1199 kore_log(LOG_ERR, "on_free callback '%s' for '%s' not found",
1200 name, current_route->path);
1201 return (KORE_RESULT_ERROR);
1202 }
1203
1204 return (KORE_RESULT_OK);
1205 }
1206
1207 static int
1208 configure_route_authenticate(char *name)
1209 {
1210 if (current_route == NULL) {
1211 kore_log(LOG_ERR,
1212 "authenticate keyword not inside of route context");
1213 return (KORE_RESULT_ERROR);
1214 }
1215
1216 current_route->auth = kore_auth_lookup(name);
1217
1218 if (current_route->auth == NULL) {
1219 kore_log(LOG_ERR, "no such authentication '%s' for '%s' found",
1220 name, current_route->path);
1221 return (KORE_RESULT_ERROR);
1222 }
1223
1224 return (KORE_RESULT_OK);
1225 }
1226
1227 static int
1228 configure_route_methods(char *options)
1229 {
1230 int i, cnt;
1231 char *argv[10];
1232
1233 if (current_route == NULL) {
1234 kore_log(LOG_ERR,
1235 "methods keyword not inside of route context");
1236 return (KORE_RESULT_ERROR);
1237 }
1238
1239 cnt = kore_split_string(options, " ", argv, 10);
1240 if (cnt < 1) {
1241 kore_log(LOG_ERR,
1242 "bad methods option '%s', missing methods", options);
1243 return (KORE_RESULT_ERROR);
1244 }
1245
1246 current_route->methods = 0;
1247
1248 for (i = 0; i < cnt; i++) {
1249 if (!strcasecmp(argv[i], "post")) {
1250 current_route->methods |= HTTP_METHOD_POST;
1251 } else if (!strcasecmp(argv[i], "get")) {
1252 current_route->methods |= HTTP_METHOD_GET;
1253 } else if (!strcasecmp(argv[i], "put")) {
1254 current_route->methods |= HTTP_METHOD_PUT;
1255 } else if (!strcasecmp(argv[i], "delete")) {
1256 current_route->methods |= HTTP_METHOD_DELETE;
1257 } else if (!strcasecmp(argv[i], "head")) {
1258 current_route->methods |= HTTP_METHOD_HEAD;
1259 } else if (!strcasecmp(argv[i], "patch")) {
1260 current_route->methods |= HTTP_METHOD_PATCH;
1261 } else {
1262 kore_log(LOG_ERR, "unknown method: %s in method for %s",
1263 argv[i], current_route->path);
1264 return (KORE_RESULT_ERROR);
1265 }
1266 }
1267
1268 return (KORE_RESULT_OK);
1269 }
1270
1271 static int
1272 configure_return(char *options)
1273 {
1274 char *argv[3];
1275 int elm, status, err;
1276
1277 if (current_domain == NULL) {
1278 kore_log(LOG_ERR, "return keyword not in domain context");
1279 return (KORE_RESULT_ERROR);
1280 }
1281
1282 elm = kore_split_string(options, " ", argv, 3);
1283 if (elm != 2) {
1284 kore_log(LOG_ERR, "missing parameters for return");
1285 return (KORE_RESULT_ERROR);
1286 }
1287
1288 status = kore_strtonum(argv[1], 10, 400, 600, &err);
1289 if (err != KORE_RESULT_OK) {
1290 kore_log(LOG_ERR,
1291 "invalid status code on return (%s)", argv[1]);
1292 return (KORE_RESULT_ERROR);
1293 }
1294
1295 if (!http_redirect_add(current_domain, argv[0], status, NULL)) {
1296 kore_log(LOG_ERR, "invalid regex on return path");
1297 return (KORE_RESULT_ERROR);
1298 }
1299
1300 return (KORE_RESULT_OK);
1301 }
1302
1303 static int
1304 configure_redirect(char *options)
1305 {
1306 char *argv[4];
1307 int elm, status, err;
1308
1309 if (current_domain == NULL) {
1310 kore_log(LOG_ERR, "redirect keyword not in domain context");
1311 return (KORE_RESULT_ERROR);
1312 }
1313
1314 elm = kore_split_string(options, " ", argv, 4);
1315 if (elm != 3) {
1316 kore_log(LOG_ERR, "missing parameters for redirect");
1317 return (KORE_RESULT_ERROR);
1318 }
1319
1320 status = kore_strtonum(argv[1], 10, 300, 399, &err);
1321 if (err != KORE_RESULT_OK) {
1322 kore_log(LOG_ERR,
1323 "invalid status code on redirect (%s)", argv[1]);
1324 return (KORE_RESULT_ERROR);
1325 }
1326
1327 if (!http_redirect_add(current_domain, argv[0], status, argv[2])) {
1328 kore_log(LOG_ERR, "invalid regex on redirect path");
1329 return (KORE_RESULT_ERROR);
1330 }
1331
1332 return (KORE_RESULT_OK);
1333 }
1334
1335 static int
1336 configure_filemap(char *options)
1337 {
1338 char *argv[3];
1339
1340 if (current_domain == NULL) {
1341 kore_log(LOG_ERR, "filemap keyword not in domain context");
1342 return (KORE_RESULT_ERROR);
1343 }
1344
1345 kore_split_string(options, " ", argv, 3);
1346
1347 if (argv[0] == NULL || argv[1] == NULL) {
1348 kore_log(LOG_ERR, "missing parameters for filemap");
1349 return (KORE_RESULT_ERROR);
1350 }
1351
1352 if (!kore_filemap_create(current_domain, argv[1], argv[0])) {
1353 kore_log(LOG_ERR, "cannot create filemap for %s", argv[1]);
1354 return (KORE_RESULT_ERROR);
1355 }
1356
1357 return (KORE_RESULT_OK);
1358 }
1359
1360 static int
1361 configure_accesslog(char *path)
1362 {
1363 if (current_domain == NULL) {
1364 kore_debug("accesslog not specified in domain context\n");
1365 return (KORE_RESULT_ERROR);
1366 }
1367
1368 if (current_domain->accesslog != -1) {
1369 kore_log(LOG_ERR, "domain '%s' already has an open accesslog",
1370 current_domain->domain);
1371 return (KORE_RESULT_ERROR);
1372 }
1373
1374 current_domain->accesslog = open(path,
1375 O_CREAT | O_APPEND | O_WRONLY,
1376 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
1377 if (current_domain->accesslog == -1) {
1378 kore_log(LOG_ERR, "accesslog open(%s): %s", path, errno_s);
1379 return (KORE_RESULT_ERROR);
1380 }
1381
1382 return (KORE_RESULT_OK);
1383 }
1384
1385 static int
1386 configure_filemap_ext(char *ext)
1387 {
1388 kore_free(kore_filemap_ext);
1389 kore_filemap_ext = kore_strdup(ext);
1390
1391 return (KORE_RESULT_OK);
1392 }
1393
1394 static int
1395 configure_filemap_index(char *index)
1396 {
1397 kore_free(kore_filemap_index);
1398 kore_filemap_index = kore_strdup(index);
1399
1400 return (KORE_RESULT_OK);
1401 }
1402
1403 static int
1404 configure_http_media_type(char *type)
1405 {
1406 int i;
1407 char *extensions, *ext[10];
1408
1409 extensions = strchr(type, ' ');
1410 if (extensions == NULL) {
1411 kore_log(LOG_ERR, "bad http_media_type value '%s'", type);
1412 return (KORE_RESULT_ERROR);
1413 }
1414
1415 *(extensions)++ = '\0';
1416
1417 kore_split_string(extensions, " \t", ext, 10);
1418 for (i = 0; ext[i] != NULL; i++) {
1419 if (!http_media_register(ext[i], type)) {
1420 kore_log(LOG_ERR,
1421 "duplicate extension found '%s'", ext[i]);
1422 return (KORE_RESULT_ERROR);
1423 }
1424 }
1425
1426 if (i == 0) {
1427 kore_log(LOG_ERR, "missing extensions in '%s'", type);
1428 return (KORE_RESULT_ERROR);
1429 }
1430
1431 return (KORE_RESULT_OK);
1432 }
1433
1434 static int
1435 configure_http_header_max(char *option)
1436 {
1437 int err;
1438
1439 http_header_max = kore_strtonum(option, 10, 1, 65535, &err);
1440 if (err != KORE_RESULT_OK) {
1441 kore_log(LOG_ERR, "bad http_header_max value '%s'", option);
1442 return (KORE_RESULT_ERROR);
1443 }
1444
1445 return (KORE_RESULT_OK);
1446 }
1447
1448 static int
1449 configure_http_header_timeout(char *option)
1450 {
1451 int err;
1452
1453 http_header_timeout = kore_strtonum(option, 10, 1, 65535, &err);
1454 if (err != KORE_RESULT_OK) {
1455 kore_log(LOG_ERR, "bad http_header_timeout value '%s'", option);
1456 return (KORE_RESULT_ERROR);
1457 }
1458
1459 return (KORE_RESULT_OK);
1460 }
1461
1462 static int
1463 configure_http_body_max(char *option)
1464 {
1465 int err;
1466
1467 http_body_max = kore_strtonum(option, 10, 0, LONG_MAX, &err);
1468 if (err != KORE_RESULT_OK) {
1469 kore_log(LOG_ERR, "bad http_body_max value '%s'", option);
1470 return (KORE_RESULT_ERROR);
1471 }
1472
1473 return (KORE_RESULT_OK);
1474 }
1475
1476 static int
1477 configure_http_body_timeout(char *option)
1478 {
1479 int err;
1480
1481 http_body_timeout = kore_strtonum(option, 10, 1, 65535, &err);
1482 if (err != KORE_RESULT_OK) {
1483 kore_log(LOG_ERR, "bad http_body_timeout value '%s'", option);
1484 return (KORE_RESULT_ERROR);
1485 }
1486
1487 return (KORE_RESULT_OK);
1488 }
1489
1490 static int
1491 configure_http_body_disk_offload(char *option)
1492 {
1493 int err;
1494
1495 http_body_disk_offload = kore_strtonum(option, 10, 0, LONG_MAX, &err);
1496 if (err != KORE_RESULT_OK) {
1497 kore_log(LOG_ERR,
1498 "bad http_body_disk_offload value '%s'", option);
1499 return (KORE_RESULT_ERROR);
1500 }
1501
1502 return (KORE_RESULT_OK);
1503 }
1504
1505 static int
1506 configure_http_body_disk_path(char *path)
1507 {
1508 if (strcmp(http_body_disk_path, HTTP_BODY_DISK_PATH))
1509 kore_free(http_body_disk_path);
1510
1511 http_body_disk_path = kore_strdup(path);
1512 return (KORE_RESULT_OK);
1513 }
1514
1515 static int
1516 configure_http_server_version(char *version)
1517 {
1518 http_server_version(version);
1519
1520 return (KORE_RESULT_OK);
1521 }
1522
1523 static int
1524 configure_http_pretty_error(char *yesno)
1525 {
1526 if (!strcmp(yesno, "no")) {
1527 http_pretty_error = 0;
1528 } else if (!strcmp(yesno, "yes")) {
1529 http_pretty_error = 1;
1530 } else {
1531 kore_log(LOG_ERR,
1532 "invalid '%s' for yes|no http_pretty_error option", yesno);
1533 return (KORE_RESULT_ERROR);
1534 }
1535
1536 return (KORE_RESULT_OK);
1537 }
1538
1539 static int
1540 configure_http_hsts_enable(char *option)
1541 {
1542 int err;
1543
1544 http_hsts_enable = kore_strtonum(option, 10, 0, LONG_MAX, &err);
1545 if (err != KORE_RESULT_OK) {
1546 kore_log(LOG_ERR, "bad http_hsts_enable value '%s'", option);
1547 return (KORE_RESULT_ERROR);
1548 }
1549
1550 return (KORE_RESULT_OK);
1551 }
1552
1553 static int
1554 configure_http_keepalive_time(char *option)
1555 {
1556 int err;
1557
1558 http_keepalive_time = kore_strtonum(option, 10, 0, USHRT_MAX, &err);
1559 if (err != KORE_RESULT_OK) {
1560 kore_log(LOG_ERR,
1561 "bad http_keepalive_time value '%s'", option);
1562 return (KORE_RESULT_ERROR);
1563 }
1564
1565 return (KORE_RESULT_OK);
1566 }
1567
1568 static int
1569 configure_http_request_ms(char *option)
1570 {
1571 int err;
1572
1573 http_request_ms = kore_strtonum(option, 10, 0, UINT_MAX, &err);
1574 if (err != KORE_RESULT_OK) {
1575 kore_log(LOG_ERR, "bad http_request_ms value '%s'", option);
1576 return (KORE_RESULT_ERROR);
1577 }
1578
1579 return (KORE_RESULT_OK);
1580 }
1581
1582 static int
1583 configure_http_request_limit(char *option)
1584 {
1585 int err;
1586
1587 http_request_limit = kore_strtonum(option, 10, 0, UINT_MAX, &err);
1588 if (err != KORE_RESULT_OK) {
1589 kore_log(LOG_ERR, "bad http_request_limit value '%s'", option);
1590 return (KORE_RESULT_ERROR);
1591 }
1592
1593 return (KORE_RESULT_OK);
1594 }
1595
1596 static int
1597 configure_validator(char *name)
1598 {
1599 u_int8_t type;
1600 char *tname, *value;
1601
1602 if ((tname = strchr(name, ' ')) == NULL) {
1603 kore_log(LOG_ERR, "missing validator name");
1604 return (KORE_RESULT_ERROR);
1605 }
1606
1607 *(tname)++ = '\0';
1608 tname = kore_text_trim(tname, strlen(tname));
1609 if ((value = strchr(tname, ' ')) == NULL) {
1610 kore_log(LOG_ERR, "missing validator value");
1611 return (KORE_RESULT_ERROR);
1612 }
1613
1614 *(value)++ = '\0';
1615 value = kore_text_trim(value, strlen(value));
1616
1617 if (!strcmp(tname, "regex")) {
1618 type = KORE_VALIDATOR_TYPE_REGEX;
1619 } else if (!strcmp(tname, "function")) {
1620 type = KORE_VALIDATOR_TYPE_FUNCTION;
1621 } else {
1622 kore_log(LOG_ERR,
1623 "bad type '%s' for validator '%s'", tname, name);
1624 return (KORE_RESULT_ERROR);
1625 }
1626
1627 if (!kore_validator_add(name, type, value)) {
1628 kore_log(LOG_ERR, "bad validator specified for '%s'", name);
1629 return (KORE_RESULT_ERROR);
1630 }
1631
1632 return (KORE_RESULT_OK);
1633 }
1634
1635 static int
1636 configure_validate(char *options)
1637 {
1638 struct kore_validator *val;
1639 struct kore_route_params *param;
1640 char *method, *argv[4];
1641 int flags, http_method;
1642
1643 if (kore_split_string(options, " ", argv, 4) != 3) {
1644 kore_log(LOG_ERR,
1645 "validate keyword needs 3 args: method param validator");
1646 return (KORE_RESULT_ERROR);
1647 }
1648
1649 flags = 0;
1650
1651 if ((method = strchr(argv[0], ':')) != NULL) {
1652 *(method)++ = '\0';
1653 if (!strcasecmp(argv[0], "qs")) {
1654 flags = KORE_PARAMS_QUERY_STRING;
1655 } else {
1656 kore_log(LOG_ERR,
1657 "unknown validate method prefix '%s' for '%s'",
1658 argv[0], current_route->path);
1659 return (KORE_RESULT_ERROR);
1660 }
1661 } else {
1662 method = argv[0];
1663 }
1664
1665 if ((val = kore_validator_lookup(argv[2])) == NULL) {
1666 kore_log(LOG_ERR, "unknown validator '%s'", argv[2]);
1667 return (KORE_RESULT_ERROR);
1668 }
1669
1670 if (!strcasecmp(method, "post")) {
1671 http_method = HTTP_METHOD_POST;
1672 } else if (!strcasecmp(method, "get")) {
1673 http_method = HTTP_METHOD_GET;
1674 /* Let params get /foo {} imply qs:get automatically. */
1675 flags |= KORE_PARAMS_QUERY_STRING;
1676 } else if (!strcasecmp(method, "put")) {
1677 http_method = HTTP_METHOD_PUT;
1678 } else if (!strcasecmp(method, "delete")) {
1679 http_method = HTTP_METHOD_DELETE;
1680 } else if (!strcasecmp(method, "head")) {
1681 http_method = HTTP_METHOD_HEAD;
1682 } else if (!strcasecmp(method, "patch")) {
1683 http_method = HTTP_METHOD_PATCH;
1684 } else {
1685 kore_log(LOG_ERR, "unknown method: %s in validator for %s",
1686 method, current_route->path);
1687 return (KORE_RESULT_ERROR);
1688 }
1689
1690 if (!(current_route->methods & http_method)) {
1691 kore_log(LOG_ERR, "method '%s' not enabled for route '%s'",
1692 method, current_route->path);
1693 return (KORE_RESULT_ERROR);
1694 }
1695
1696 param = kore_calloc(1, sizeof(*param));
1697
1698 param->flags = flags;
1699 param->validator = val;
1700 param->method = http_method;
1701 param->name = kore_strdup(argv[1]);
1702
1703 TAILQ_INSERT_TAIL(¤t_route->params, param, list);
1704
1705 return (KORE_RESULT_OK);
1706 }
1707
1708 static int
1709 configure_authentication(char *options)
1710 {
1711 char *argv[3];
1712
1713 if (current_auth != NULL) {
1714 kore_log(LOG_ERR, "previous authentication block not closed");
1715 return (KORE_RESULT_ERROR);
1716 }
1717
1718 kore_split_string(options, " ", argv, 3);
1719 if (argv[1] == NULL) {
1720 kore_log(LOG_ERR, "missing name for authentication block");
1721 return (KORE_RESULT_ERROR);
1722 }
1723
1724 if (strcmp(argv[1], "{")) {
1725 kore_log(LOG_ERR, "missing { for authentication block");
1726 return (KORE_RESULT_ERROR);
1727 }
1728
1729 if (!kore_auth_new(argv[0]))
1730 return (KORE_RESULT_ERROR);
1731
1732 current_auth = kore_auth_lookup(argv[0]);
1733
1734 return (KORE_RESULT_OK);
1735 }
1736
1737 static int
1738 configure_authentication_type(char *option)
1739 {
1740 if (current_auth == NULL) {
1741 kore_log(LOG_ERR,
1742 "authentication_type keyword not in correct context");
1743 return (KORE_RESULT_ERROR);
1744 }
1745
1746 if (!strcmp(option, "cookie")) {
1747 current_auth->type = KORE_AUTH_TYPE_COOKIE;
1748 } else if (!strcmp(option, "header")) {
1749 current_auth->type = KORE_AUTH_TYPE_HEADER;
1750 } else if (!strcmp(option, "request")) {
1751 current_auth->type = KORE_AUTH_TYPE_REQUEST;
1752 } else {
1753 kore_log(LOG_ERR, "unknown authentication type '%s'", option);
1754 return (KORE_RESULT_ERROR);
1755 }
1756
1757 return (KORE_RESULT_OK);
1758 }
1759
1760 static int
1761 configure_authentication_value(char *option)
1762 {
1763 if (current_auth == NULL) {
1764 kore_log(LOG_ERR,
1765 "authentication_value keyword not in correct context");
1766 return (KORE_RESULT_ERROR);
1767 }
1768
1769 if (current_auth->value != NULL)
1770 kore_free(current_auth->value);
1771 current_auth->value = kore_strdup(option);
1772
1773 return (KORE_RESULT_OK);
1774 }
1775
1776 static int
1777 configure_authentication_validator(char *validator)
1778 {
1779 struct kore_validator *val;
1780
1781 if (current_auth == NULL) {
1782 kore_log(LOG_ERR,
1783 "authentication_validator not in correct context");
1784 return (KORE_RESULT_ERROR);
1785 }
1786
1787 if ((val = kore_validator_lookup(validator)) == NULL) {
1788 kore_log(LOG_ERR,
1789 "authentication validator '%s' not found", validator);
1790 return (KORE_RESULT_ERROR);
1791 }
1792
1793 current_auth->validator = val;
1794
1795 return (KORE_RESULT_OK);
1796 }
1797
1798 static int
1799 configure_authentication_uri(char *uri)
1800 {
1801 if (current_auth == NULL) {
1802 kore_log(LOG_ERR,
1803 "authentication_uri keyword not in correct context");
1804 return (KORE_RESULT_ERROR);
1805 }
1806
1807 if (current_auth->redirect != NULL)
1808 kore_free(current_auth->redirect);
1809 current_auth->redirect = kore_strdup(uri);
1810
1811 return (KORE_RESULT_OK);
1812 }
1813
1814 static int
1815 configure_websocket_maxframe(char *option)
1816 {
1817 int err;
1818
1819 kore_websocket_maxframe = kore_strtonum64(option, 1, &err);
1820 if (err != KORE_RESULT_OK) {
1821 kore_log(LOG_ERR,
1822 "bad kore_websocket_maxframe value '%s'", option);
1823 return (KORE_RESULT_ERROR);
1824 }
1825
1826 return (KORE_RESULT_OK);
1827 }
1828
1829 static int
1830 configure_websocket_timeout(char *option)
1831 {
1832 int err;
1833
1834 kore_websocket_timeout = kore_strtonum64(option, 1, &err);
1835 if (err != KORE_RESULT_OK) {
1836 kore_log(LOG_ERR,
1837 "bad kore_websocket_timeout value '%s'", option);
1838 return (KORE_RESULT_ERROR);
1839 }
1840
1841 kore_websocket_timeout = kore_websocket_timeout * 1000;
1842
1843 return (KORE_RESULT_OK);
1844 }
1845
1846 #endif /* !KORE_NO_HTTP */
1847
1848 static int
1849 configure_logfile(char *path)
1850 {
1851 kore_log_file(path);
1852 return (KORE_RESULT_OK);
1853 }
1854
1855 static int
1856 configure_workers(char *option)
1857 {
1858 int err;
1859
1860 worker_count = kore_strtonum(option, 10, 1, KORE_WORKER_MAX, &err);
1861 if (err != KORE_RESULT_OK) {
1862 kore_log(LOG_ERR, "bad value for worker '%s'", option);
1863 return (KORE_RESULT_ERROR);
1864 }
1865
1866 return (KORE_RESULT_OK);
1867 }
1868
1869 static int
1870 configure_pidfile(char *path)
1871 {
1872 if (strcmp(kore_pidfile, KORE_PIDFILE_DEFAULT))
1873 kore_free(kore_pidfile);
1874 kore_pidfile = kore_strdup(path);
1875
1876 return (KORE_RESULT_OK);
1877 }
1878
1879 static int
1880 configure_max_connections(char *option)
1881 {
1882 int err;
1883
1884 worker_max_connections = kore_strtonum(option, 10, 1, UINT_MAX, &err);
1885 if (err != KORE_RESULT_OK) {
1886 kore_log(LOG_ERR,
1887 "bad value for worker_max_connections '%s'", option);
1888 return (KORE_RESULT_ERROR);
1889 }
1890
1891 return (KORE_RESULT_OK);
1892 }
1893
1894 static int
1895 configure_rlimit_nofiles(char *option)
1896 {
1897 int err;
1898
1899 worker_rlimit_nofiles = kore_strtonum(option, 10, 1, UINT_MAX, &err);
1900 if (err != KORE_RESULT_OK) {
1901 kore_log(LOG_ERR,
1902 "bad value for worker_rlimit_nofiles '%s'", option);
1903 return (KORE_RESULT_ERROR);
1904 }
1905
1906 return (KORE_RESULT_OK);
1907 }
1908
1909 static int
1910 configure_accept_threshold(char *option)
1911 {
1912 int err;
1913
1914 worker_accept_threshold = kore_strtonum(option, 0, 1, UINT_MAX, &err);
1915 if (err != KORE_RESULT_OK) {
1916 kore_log(LOG_ERR,
1917 "bad value for worker_accept_threshold '%s'\n", option);
1918 return (KORE_RESULT_ERROR);
1919 }
1920
1921 return (KORE_RESULT_OK);
1922 }
1923
1924 static int
1925 configure_death_policy(char *option)
1926 {
1927 if (!strcmp(option, "restart")) {
1928 worker_policy = KORE_WORKER_POLICY_RESTART;
1929 } else if (!strcmp(option, "terminate")) {
1930 worker_policy = KORE_WORKER_POLICY_TERMINATE;
1931 } else {
1932 kore_log(LOG_ERR,
1933 "bad value for worker_death_policy '%s'\n", option);
1934 return (KORE_RESULT_ERROR);
1935 }
1936
1937 return (KORE_RESULT_OK);
1938 }
1939
1940 static int
1941 configure_set_affinity(char *option)
1942 {
1943 int err;
1944
1945 worker_set_affinity = kore_strtonum(option, 10, 0, 1, &err);
1946 if (err != KORE_RESULT_OK) {
1947 kore_log(LOG_ERR,
1948 "bad value for worker_set_affinity '%s'", option);
1949 return (KORE_RESULT_ERROR);
1950 }
1951
1952 return (KORE_RESULT_OK);
1953 }
1954
1955 static int
1956 configure_socket_backlog(char *option)
1957 {
1958 int err;
1959
1960 kore_socket_backlog = kore_strtonum(option, 10, 0, UINT_MAX, &err);
1961 if (err != KORE_RESULT_OK) {
1962 kore_log(LOG_ERR, "bad socket_backlog value: '%s'", option);
1963 return (KORE_RESULT_ERROR);
1964 }
1965
1966 return (KORE_RESULT_OK);
1967 }
1968
1969 #if defined(KORE_USE_PGSQL)
1970 static int
1971 configure_pgsql_conn_max(char *option)
1972 {
1973 int err;
1974
1975 pgsql_conn_max = kore_strtonum(option, 10, 0, USHRT_MAX, &err);
1976 if (err != KORE_RESULT_OK) {
1977 kore_log(LOG_ERR, "bad value for pgsql_conn_max '%s'", option);
1978 return (KORE_RESULT_ERROR);
1979 }
1980
1981 return (KORE_RESULT_OK);
1982 }
1983
1984 static int
1985 configure_pgsql_queue_limit(char *option)
1986 {
1987 int err;
1988
1989 pgsql_queue_limit = kore_strtonum(option, 10, 0, UINT_MAX, &err);
1990 if (err != KORE_RESULT_OK) {
1991 kore_log(LOG_ERR,
1992 "bad value for pgsql_queue_limit '%s'", option);
1993 return (KORE_RESULT_ERROR);
1994 }
1995
1996 return (KORE_RESULT_OK);
1997 }
1998 #endif
1999
2000 #if defined(KORE_USE_TASKS)
2001 static int
2002 configure_task_threads(char *option)
2003 {
2004 int err;
2005
2006 kore_task_threads = kore_strtonum(option, 10, 0, UCHAR_MAX, &err);
2007 if (err != KORE_RESULT_OK) {
2008 kore_log(LOG_ERR, "bad value for task_threads: '%s'", option);
2009 return (KORE_RESULT_ERROR);
2010 }
2011
2012 return (KORE_RESULT_OK);
2013 }
2014 #endif
2015
2016 #if defined(KORE_USE_PYTHON)
2017 static int
2018 configure_deployment(char *value)
2019 {
2020 if (!strcmp(value, "docker")) {
2021 kore_foreground = 1;
2022 skip_runas = 0;
2023 skip_chroot = 0;
2024 } else if (!strcmp(value, "dev") || !strcmp(value, "development")) {
2025 kore_foreground = 1;
2026 skip_runas = 1;
2027 skip_chroot = 1;
2028 } else if (!strcmp(value, "production")) {
2029 kore_foreground = 0;
2030 skip_runas = 0;
2031 skip_chroot = 0;
2032 } else {
2033 kore_log(LOG_NOTICE,
2034 "kore.config.deployment: bad value '%s'", value);
2035 return (KORE_RESULT_ERROR);
2036 }
2037
2038 return (KORE_RESULT_OK);
2039 }
2040
2041 static int
2042 configure_python_path(char *path)
2043 {
2044 kore_python_path(path);
2045
2046 return (KORE_RESULT_OK);
2047 }
2048
2049 static int
2050 configure_python_import(char *module)
2051 {
2052 char *argv[3];
2053
2054 kore_split_string(module, " ", argv, 3);
2055 if (argv[0] == NULL)
2056 return (KORE_RESULT_ERROR);
2057
2058 kore_module_load(argv[0], argv[1], KORE_MODULE_PYTHON);
2059 return (KORE_RESULT_OK);
2060 }
2061 #endif
2062
2063 #if defined(KORE_USE_PLATFORM_PLEDGE)
2064 static int
2065 configure_add_pledge(char *pledge)
2066 {
2067 kore_platform_add_pledge(pledge);
2068
2069 return (KORE_RESULT_OK);
2070 }
2071 #endif
2072
2073 #if defined(KORE_USE_CURL)
2074 static int
2075 configure_curl_recv_max(char *option)
2076 {
2077 int err;
2078
2079 kore_curl_recv_max = kore_strtonum64(option, 1, &err);
2080 if (err != KORE_RESULT_OK) {
2081 kore_log(LOG_ERR, "bad curl_recv_max value '%s'\n", option);
2082 return (KORE_RESULT_ERROR);
2083 }
2084
2085 return (KORE_RESULT_OK);
2086 }
2087
2088 static int
2089 configure_curl_timeout(char *option)
2090 {
2091 int err;
2092
2093 kore_curl_timeout = kore_strtonum(option, 10, 0, USHRT_MAX, &err);
2094 if (err != KORE_RESULT_OK) {
2095 kore_log(LOG_ERR, "bad kore_curl_timeout value: '%s'", option);
2096 return (KORE_RESULT_ERROR);
2097 }
2098
2099 return (KORE_RESULT_OK);
2100 }
2101 #endif
2102
2103 #if defined(__linux__)
2104 static int
2105 configure_seccomp_tracing(char *opt)
2106 {
2107 if (!strcmp(opt, "yes")) {
2108 kore_seccomp_tracing = 1;
2109 } else if (!strcmp(opt, "no")) {
2110 kore_seccomp_tracing = 0;
2111 } else {
2112 kore_log(LOG_ERR,
2113 "bad seccomp_tracing value '%s' (expected yes|no)\n", opt);
2114 return (KORE_RESULT_ERROR);
2115 }
2116
2117 return (KORE_RESULT_OK);
2118 }
2119 #endif