kore

An easy to use, scalable and secure web application framework for writing web APIs in C.
Commits | Files | Refs | README | LICENSE | git clone https://git.kore.io/kore.git

worker.c (22537B)



      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 #include <sys/shm.h>
     21 #include <sys/wait.h>
     22 #include <sys/time.h>
     23 #include <sys/resource.h>
     24 #include <sys/socket.h>
     25 
     26 #include <fcntl.h>
     27 #include <grp.h>
     28 #include <pwd.h>
     29 #include <signal.h>
     30 #include <unistd.h>
     31 
     32 #include "kore.h"
     33 
     34 #if defined(KORE_USE_ACME)
     35 #include "acme.h"
     36 #endif
     37 
     38 #if !defined(KORE_NO_HTTP)
     39 #include "http.h"
     40 #endif
     41 
     42 #if defined(KORE_USE_PGSQL)
     43 #include "pgsql.h"
     44 #endif
     45 
     46 #if defined(KORE_USE_TASKS)
     47 #include "tasks.h"
     48 #endif
     49 
     50 #if defined(KORE_USE_PYTHON)
     51 #include "python_api.h"
     52 #endif
     53 
     54 #if defined(KORE_USE_CURL)
     55 #include "curl.h"
     56 #endif
     57 
     58 #if defined(__linux__)
     59 #include "seccomp.h"
     60 #endif
     61 
     62 #define WORKER_SOLO_COUNT	3
     63 
     64 #define WORKER(id)						\
     65 	(struct kore_worker *)((u_int8_t *)kore_workers +	\
     66 	    (sizeof(struct kore_worker) * id))
     67 
     68 struct wlock {
     69 	volatile int		lock;
     70 	pid_t			current;
     71 };
     72 
     73 static int	worker_trylock(void);
     74 static void	worker_unlock(void);
     75 static void	worker_reaper(pid_t, int);
     76 static void	worker_runtime_teardown(void);
     77 static void	worker_runtime_configure(void);
     78 static void	worker_domain_check(struct kore_domain *);
     79 
     80 static struct kore_runtime_call	*worker_runtime_signal(void);
     81 
     82 static inline int	worker_acceptlock_obtain(void);
     83 static inline void	worker_acceptlock_release(void);
     84 static void		worker_accept_avail(struct kore_msg *, const void *);
     85 
     86 static void	worker_entropy_recv(struct kore_msg *, const void *);
     87 static void	worker_keymgr_response(struct kore_msg *, const void *);
     88 
     89 static pid_t				worker_pgrp;
     90 static int				accept_avail;
     91 static struct kore_worker		*kore_workers;
     92 static int				worker_no_lock;
     93 static int				shm_accept_key;
     94 static struct wlock			*accept_lock;
     95 
     96 struct kore_worker		*worker = NULL;
     97 u_int8_t			worker_set_affinity = 1;
     98 u_int32_t			worker_accept_threshold = 16;
     99 u_int32_t			worker_rlimit_nofiles = 768;
    100 u_int32_t			worker_max_connections = 512;
    101 u_int32_t			worker_active_connections = 0;
    102 int				worker_policy = KORE_WORKER_POLICY_RESTART;
    103 
    104 int
    105 kore_worker_init(void)
    106 {
    107 	size_t			len;
    108 	struct kore_worker	*kw;
    109 	u_int16_t		idx, id, cpu;
    110 
    111 	worker_no_lock = 0;
    112 
    113 	if (worker_count == 0)
    114 		worker_count = cpu_count;
    115 
    116 	/* Account for the keymgr/acme even if we don't end up starting it. */
    117 	worker_count += 2;
    118 
    119 	len = sizeof(*accept_lock) +
    120 	    (sizeof(struct kore_worker) * worker_count);
    121 
    122 	shm_accept_key = shmget(IPC_PRIVATE, len, IPC_CREAT | IPC_EXCL | 0700);
    123 	if (shm_accept_key == -1)
    124 		fatal("kore_worker_init(): shmget() %s", errno_s);
    125 	if ((accept_lock = shmat(shm_accept_key, NULL, 0)) == (void *)-1)
    126 		fatal("kore_worker_init(): shmat() %s", errno_s);
    127 
    128 	accept_lock->lock = 0;
    129 	accept_lock->current = 0;
    130 
    131 	kore_workers = (struct kore_worker *)((u_int8_t *)accept_lock +
    132 	    sizeof(*accept_lock));
    133 	memset(kore_workers, 0, sizeof(struct kore_worker) * worker_count);
    134 
    135 	kore_debug("kore_worker_init(): system has %d cpu's", cpu_count);
    136 	kore_debug("kore_worker_init(): starting %d workers", worker_count);
    137 
    138 	if (worker_count > cpu_count) {
    139 		kore_debug("kore_worker_init(): more workers than cpu's");
    140 	}
    141 
    142 	/* Setup log buffers. */
    143 	for (idx = KORE_WORKER_BASE; idx < worker_count; idx++) {
    144 		kw = WORKER(idx);
    145 		kw->lb.offset = 0;
    146 	}
    147 
    148 	if (!kore_quiet)
    149 		kore_log(LOG_INFO, "starting worker processes");
    150 
    151 	if ((worker_pgrp = getpgrp()) == -1)
    152 		fatal("%s: getpgrp(): %s", __func__, errno_s);
    153 
    154 	/* Now start all the workers. */
    155 	id = 1;
    156 	cpu = 1;
    157 	for (idx = KORE_WORKER_BASE; idx < worker_count; idx++) {
    158 		if (cpu >= cpu_count)
    159 			cpu = 0;
    160 		if (!kore_worker_spawn(idx, id++, cpu++))
    161 			return (KORE_RESULT_ERROR);
    162 	}
    163 
    164 	if (kore_keymgr_active) {
    165 #if defined(KORE_USE_ACME)
    166 		/* The ACME process is only started if we need it. */
    167 		if (acme_domains) {
    168 			if (!kore_worker_spawn(KORE_WORKER_ACME_IDX,
    169 			    KORE_WORKER_ACME, 0))
    170 				return (KORE_RESULT_ERROR);
    171 		}
    172 #endif
    173 
    174 		/* Now we can start the keymgr. */
    175 		if (!kore_worker_spawn(KORE_WORKER_KEYMGR_IDX,
    176 		    KORE_WORKER_KEYMGR, 0))
    177 			return (KORE_RESULT_ERROR);
    178 	}
    179 
    180 	if (!kore_quiet)
    181 		kore_log(LOG_INFO, "all worker processes started");
    182 
    183 	return (KORE_RESULT_OK);
    184 }
    185 
    186 int
    187 kore_worker_spawn(u_int16_t idx, u_int16_t id, u_int16_t cpu)
    188 {
    189 	int			cnt;
    190 	struct kore_worker	*kw;
    191 #if defined(__linux__)
    192 	int			status;
    193 #endif
    194 
    195 	kw = WORKER(idx);
    196 	kw->id = id;
    197 	kw->cpu = cpu;
    198 	kw->running = 1;
    199 
    200 	kw->ready = 0;
    201 	kw->has_lock = 0;
    202 	kw->active_route = NULL;
    203 
    204 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, kw->pipe) == -1)
    205 		fatal("socketpair(): %s", errno_s);
    206 
    207 	if (!kore_connection_nonblock(kw->pipe[0], 0) ||
    208 	    !kore_connection_nonblock(kw->pipe[1], 0))
    209 		fatal("could not set pipe fds to nonblocking: %s", errno_s);
    210 
    211 	switch (id) {
    212 	case KORE_WORKER_KEYMGR:
    213 		kw->ps = &keymgr_privsep;
    214 		break;
    215 #if defined(KORE_USE_ACME)
    216 	case KORE_WORKER_ACME:
    217 		kw->ps = &acme_privsep;
    218 		break;
    219 #endif
    220 	default:
    221 		kw->ps = &worker_privsep;
    222 		break;
    223 	}
    224 
    225 	kw->pid = fork();
    226 	if (kw->pid == -1)
    227 		fatal("could not spawn worker child: %s", errno_s);
    228 
    229 	if (kw->pid == 0) {
    230 		kw->pid = getpid();
    231 		kore_worker_entry(kw);
    232 		exit(1);
    233 	} else {
    234 		for (cnt = 0; cnt < 50; cnt++) {
    235 			if (kw->ready == 1)
    236 				break;
    237 			usleep(100000);
    238 #if defined(__linux__)
    239 			/*
    240 			 * If seccomp_tracing is enabled, make sure we
    241 			 * handle the SIGSTOP from the child processes.
    242 			 */
    243 			if (kore_seccomp_tracing) {
    244 				if (waitpid(kw->pid, &status, WNOHANG) > 0)
    245 					kore_seccomp_trace(kw->pid, status);
    246 			}
    247 #endif
    248 		}
    249 
    250 		if (kw->ready == 0) {
    251 			kore_log(LOG_NOTICE,
    252 			    "worker %d failed to start, shutting down",
    253 			    kw->id);
    254 
    255 			return (KORE_RESULT_ERROR);
    256 		}
    257 	}
    258 
    259 	return (KORE_RESULT_OK);
    260 }
    261 
    262 struct kore_worker *
    263 kore_worker_data(u_int8_t idx)
    264 {
    265 	if (idx >= worker_count)
    266 		fatal("idx %u too large for worker count", idx);
    267 
    268 	return (WORKER(idx));
    269 }
    270 
    271 struct kore_worker *
    272 kore_worker_data_byid(u_int16_t id)
    273 {
    274 	struct kore_worker	*kw;
    275 	u_int16_t		idx;
    276 
    277 	for (idx = 0; idx < worker_count; idx++) {
    278 		kw = WORKER(idx);
    279 		if (kw->id == id)
    280 			return (kw);
    281 	}
    282 
    283 	return (NULL);
    284 }
    285 
    286 void
    287 kore_worker_shutdown(void)
    288 {
    289 	struct kore_worker	*kw;
    290 	pid_t			pid;
    291 	int			status;
    292 	u_int16_t		idx, done;
    293 
    294 	if (!kore_quiet) {
    295 		kore_log(LOG_NOTICE,
    296 		    "waiting for workers to drain and shutdown");
    297 	}
    298 
    299 	for (;;) {
    300 		for (idx = 0; idx < worker_count; idx++) {
    301 			kw = WORKER(idx);
    302 			if (kw->running == 0)
    303 				continue;
    304 
    305 			if (kw->pid != 0) {
    306 				pid = waitpid(kw->pid, &status, 0);
    307 				if (pid == -1 && errno != ECHILD)
    308 					continue;
    309 
    310 #if defined(__linux__)
    311 				kore_seccomp_trace(kw->pid, status);
    312 #endif
    313 
    314 				kw->pid = 0;
    315 				kw->running = 0;
    316 
    317 				kw->msg[0]->evt.flags |= KORE_EVENT_READ;
    318 				net_recv_flush(kw->msg[0]);
    319 
    320 				if (!kore_quiet) {
    321 					kore_log(LOG_NOTICE,
    322 					    "worker %s exited (%d)",
    323 					    kore_worker_name(kw->id), status);
    324 				}
    325 			}
    326 		}
    327 
    328 		done = 0;
    329 		for (idx = 0; idx < worker_count; idx++) {
    330 			kw = WORKER(idx);
    331 			if (kw->running == 0) {
    332 				done++;
    333 				continue;
    334 			}
    335 		}
    336 
    337 		if (done == worker_count)
    338 			break;
    339 	}
    340 
    341 	if (shmctl(shm_accept_key, IPC_RMID, NULL) == -1) {
    342 		kore_log(LOG_NOTICE,
    343 		    "failed to deleted shm segment: %s", errno_s);
    344 	}
    345 }
    346 
    347 void
    348 kore_worker_dispatch_signal(int sig)
    349 {
    350 	u_int16_t		idx;
    351 	struct kore_worker	*kw;
    352 
    353 	for (idx = 0; idx < worker_count; idx++) {
    354 		kw = WORKER(idx);
    355 
    356 		if (kw->pid == -1 || kw->pid == 0)
    357 			continue;
    358 
    359 		if (kill(kw->pid, sig) == -1) {
    360 			kore_debug("kill(%d, %d): %s", kw->pid, sig, errno_s);
    361 		}
    362 	}
    363 }
    364 
    365 void
    366 kore_worker_privsep(void)
    367 {
    368 	rlim_t			fd;
    369 	struct rlimit		rl;
    370 	struct passwd		*pw;
    371 
    372 	if (worker == NULL)
    373 		fatalx("%s called with no worker", __func__);
    374 
    375 	pw = NULL;
    376 
    377 	/* Must happen before chroot. */
    378 	if (worker->ps->skip_runas == 0) {
    379 		if (worker->ps->runas == NULL) {
    380 			fatalx("no runas user given for %s",
    381 			    kore_worker_name(worker->id));
    382 		}
    383 
    384 		if ((pw = getpwnam(worker->ps->runas)) == NULL) {
    385 			fatalx("cannot getpwnam(\"%s\") for user: %s",
    386 			    worker->ps->runas, errno_s);
    387 		}
    388 	}
    389 
    390 	if (worker->ps->skip_chroot == 0) {
    391 		if (chroot(worker->ps->root) == -1) {
    392 			fatalx("cannot chroot(\"%s\"): %s",
    393 			    worker->ps->root, errno_s);
    394 		}
    395 
    396 		if (chdir("/") == -1)
    397 			fatalx("cannot chdir(\"/\"): %s", errno_s);
    398 	} else {
    399 		if (chdir(worker->ps->root) == -1) {
    400 			fatalx("cannot chdir(\"%s\"): %s",
    401 			    worker->ps->root, errno_s);
    402 		}
    403 	}
    404 
    405 	if (getrlimit(RLIMIT_NOFILE, &rl) == -1) {
    406 		kore_log(LOG_WARNING, "getrlimit(RLIMIT_NOFILE): %s", errno_s);
    407 	} else {
    408 		for (fd = 0; fd < rl.rlim_cur; fd++) {
    409 			if (fcntl(fd, F_GETFD, NULL) != -1) {
    410 				worker_rlimit_nofiles++;
    411 			}
    412 		}
    413 	}
    414 
    415 	rl.rlim_cur = worker_rlimit_nofiles;
    416 	rl.rlim_max = worker_rlimit_nofiles;
    417 	if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
    418 		kore_log(LOG_ERR, "setrlimit(RLIMIT_NOFILE, %u): %s",
    419 		    worker_rlimit_nofiles, errno_s);
    420 	}
    421 
    422 	if (worker->ps->skip_runas == 0) {
    423 		if (setgroups(1, &pw->pw_gid) ||
    424 #if defined(__MACH__) || defined(NetBSD)
    425 		    setgid(pw->pw_gid) || setegid(pw->pw_gid) ||
    426 		    setuid(pw->pw_uid) || seteuid(pw->pw_uid))
    427 #else
    428 		    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
    429 		    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
    430 #endif
    431 			fatalx("cannot drop privileges (%s)", errno_s);
    432 	}
    433 
    434 	kore_platform_sandbox();
    435 }
    436 
    437 void
    438 kore_worker_entry(struct kore_worker *kw)
    439 {
    440 	struct kore_runtime_call	*sigcall;
    441 	u_int64_t			last_seed;
    442 	int				quit, had_lock, sig;
    443 	u_int64_t			netwait, now, next_timeo;
    444 
    445 	worker = kw;
    446 
    447 	if (!kore_foreground)
    448 		closelog();
    449 
    450 #if defined(__linux__)
    451 	kore_seccomp_traceme();
    452 #endif
    453 
    454 	kore_platform_proctitle(kore_worker_name(kw->id));
    455 
    456 	if (worker_set_affinity == 1)
    457 		kore_platform_worker_setcpu(kw);
    458 
    459 	kore_pid = kw->pid;
    460 	kore_signal_setup();
    461 
    462 	if (kw->id == KORE_WORKER_KEYMGR) {
    463 		kore_keymgr_run();
    464 		exit(0);
    465 	}
    466 
    467 #if defined(KORE_USE_ACME)
    468 	if (kw->id == KORE_WORKER_ACME) {
    469 		kore_acme_run();
    470 		exit(0);
    471 	}
    472 #endif
    473 
    474 	net_init();
    475 	kore_connection_init();
    476 	kore_platform_event_init();
    477 	kore_msg_worker_init();
    478 
    479 #if defined(KORE_USE_TASKS)
    480 	kore_task_init();
    481 #endif
    482 
    483 	kore_worker_privsep();
    484 
    485 #if !defined(KORE_NO_HTTP)
    486 	http_init();
    487 	kore_filemap_resolve_paths();
    488 	kore_accesslog_worker_init();
    489 #endif
    490 	kore_timer_init();
    491 	kore_fileref_init();
    492 	kore_tls_keymgr_init();
    493 
    494 	quit = 0;
    495 	had_lock = 0;
    496 	next_timeo = 0;
    497 	accept_avail = 1;
    498 	worker_active_connections = 0;
    499 
    500 	last_seed = 0;
    501 
    502 	if (kore_keymgr_active) {
    503 		kore_msg_register(KORE_MSG_CRL, worker_keymgr_response);
    504 		kore_msg_register(KORE_MSG_ENTROPY_RESP, worker_entropy_recv);
    505 		kore_msg_register(KORE_MSG_CERTIFICATE, worker_keymgr_response);
    506 
    507 		if (worker->restarted) {
    508 			kore_msg_send(KORE_WORKER_KEYMGR,
    509 			    KORE_MSG_CERTIFICATE_REQ, NULL, 0);
    510 		}
    511 #if defined(KORE_USE_ACME)
    512 		kore_msg_register(KORE_ACME_CHALLENGE_SET_CERT,
    513 		    worker_keymgr_response);
    514 		kore_msg_register(KORE_ACME_CHALLENGE_CLEAR_CERT,
    515 		    worker_keymgr_response);
    516 #endif
    517 	}
    518 
    519 	kore_msg_register(KORE_MSG_ACCEPT_AVAILABLE, worker_accept_avail);
    520 
    521 	if (nlisteners == 0)
    522 		worker_no_lock = 1;
    523 
    524 	worker_runtime_configure();
    525 
    526 	kore_module_onload();
    527 	kore_domain_callback(worker_domain_check);
    528 
    529 	kore_worker_started();
    530 	worker->restarted = 0;
    531 
    532 	sigcall = worker_runtime_signal();
    533 
    534 	for (;;) {
    535 		now = kore_time_ms();
    536 
    537 		if (kore_keymgr_active &&
    538 		    (now - last_seed) > KORE_RESEED_TIME) {
    539 			kore_msg_send(KORE_WORKER_KEYMGR,
    540 			    KORE_MSG_ENTROPY_REQ, NULL, 0);
    541 			last_seed = now;
    542 		}
    543 
    544 		if (!worker->has_lock && accept_avail) {
    545 			if (worker_acceptlock_obtain()) {
    546 				accept_avail = 0;
    547 				if (had_lock == 0) {
    548 					kore_platform_enable_accept();
    549 					had_lock = 1;
    550 				}
    551 			}
    552 		}
    553 
    554 		netwait = kore_timer_next_run(now);
    555 
    556 		if (netwait == KORE_WAIT_INFINITE) {
    557 			if (sig_recv != 0)
    558 				netwait = 10;
    559 #if !defined(KORE_NO_HTTP)
    560 			if (http_request_count > 0)
    561 				netwait = 100;
    562 #endif
    563 		}
    564 
    565 #if defined(KORE_USE_PYTHON)
    566 		if (kore_python_coro_pending())
    567 			netwait = 0;
    568 #endif
    569 
    570 		kore_platform_event_wait(netwait);
    571 		now = kore_time_ms();
    572 
    573 		if (worker->has_lock)
    574 			worker_acceptlock_release();
    575 
    576 		if (!worker->has_lock) {
    577 			if (had_lock == 1) {
    578 				had_lock = 0;
    579 				kore_platform_disable_accept();
    580 			}
    581 		}
    582 
    583 		sig = sig_recv;
    584 		if (sig != 0) {
    585 			switch (sig) {
    586 			case SIGHUP:
    587 				kore_module_reload(1);
    588 				break;
    589 			case SIGQUIT:
    590 			case SIGINT:
    591 			case SIGTERM:
    592 				quit = 1;
    593 				break;
    594 			case SIGCHLD:
    595 #if defined(KORE_USE_PYTHON)
    596 				kore_python_proc_reap();
    597 #endif
    598 				break;
    599 			default:
    600 				break;
    601 			}
    602 
    603 			if (sigcall != NULL)
    604 				kore_runtime_signal(sigcall, sig);
    605 
    606 			if (sig == sig_recv)
    607 				sig_recv = 0;
    608 		}
    609 
    610 		if (quit)
    611 			break;
    612 
    613 		kore_timer_run(now);
    614 #if defined(KORE_USE_CURL)
    615 		kore_curl_run_scheduled();
    616 		kore_curl_do_timeout();
    617 #endif
    618 #if !defined(KORE_NO_HTTP)
    619 		http_process();
    620 #endif
    621 #if defined(KORE_USE_PYTHON)
    622 		kore_python_coro_run();
    623 #endif
    624 		if (next_timeo <= now) {
    625 			kore_connection_check_timeout(now);
    626 			next_timeo = now + 500;
    627 		}
    628 
    629 		kore_connection_prune(KORE_CONNECTION_PRUNE_DISCONNECT);
    630 	}
    631 
    632 	worker_runtime_teardown();
    633 	kore_server_cleanup();
    634 
    635 	kore_platform_event_cleanup();
    636 	kore_connection_cleanup();
    637 	kore_domain_cleanup();
    638 	kore_tls_cleanup();
    639 	kore_module_cleanup();
    640 #if !defined(KORE_NO_HTTP)
    641 	http_cleanup();
    642 #endif
    643 	net_cleanup();
    644 
    645 #if defined(KORE_USE_PYTHON)
    646 	kore_python_cleanup();
    647 #endif
    648 
    649 #if defined(KORE_USE_PGSQL)
    650 	kore_pgsql_sys_cleanup();
    651 #endif
    652 
    653 	kore_debug("worker %d shutting down", kw->id);
    654 
    655 	kore_mem_cleanup();
    656 	exit(0);
    657 }
    658 
    659 void
    660 kore_worker_reap(void)
    661 {
    662 	pid_t			pid;
    663 	int			status;
    664 
    665 	for (;;) {
    666 		pid = waitpid(-worker_pgrp, &status, WNOHANG);
    667 
    668 		if (pid == -1) {
    669 			if (errno != ECHILD && errno != EINTR) {
    670 				kore_log(LOG_ERR,
    671 				    "%s: waitpid(): %s", __func__, errno_s);
    672 			}
    673 			break;
    674 		}
    675 
    676 		if (pid == 0)
    677 			break;
    678 
    679 		worker_reaper(pid, status);
    680 	}
    681 }
    682 
    683 void
    684 kore_worker_make_busy(void)
    685 {
    686 	if (worker_count == WORKER_SOLO_COUNT || worker_no_lock == 1)
    687 		return;
    688 
    689 	if (worker->has_lock) {
    690 		worker_unlock();
    691 		worker->has_lock = 0;
    692 		kore_msg_send(KORE_MSG_WORKER_ALL,
    693 		    KORE_MSG_ACCEPT_AVAILABLE, NULL, 0);
    694 	}
    695 }
    696 
    697 int
    698 kore_worker_keymgr_response_verify(struct kore_msg *msg, const void *data,
    699     struct kore_domain **out)
    700 {
    701 	struct kore_server		*srv;
    702 	struct kore_domain		*dom;
    703 	const struct kore_x509_msg	*req;
    704 
    705 	if (msg->length < sizeof(*req)) {
    706 		kore_log(LOG_WARNING,
    707 		    "short keymgr message (%zu)", msg->length);
    708 		return (KORE_RESULT_ERROR);
    709 	}
    710 
    711 	req = (const struct kore_x509_msg *)data;
    712 	if (msg->length != (sizeof(*req) + req->data_len)) {
    713 		kore_log(LOG_WARNING,
    714 		    "invalid keymgr payload (%zu)", msg->length);
    715 		return (KORE_RESULT_ERROR);
    716 	}
    717 
    718 	if (req->domain[KORE_DOMAINNAME_LEN] != '\0') {
    719 		kore_log(LOG_WARNING, "domain not NUL-terminated");
    720 		return (KORE_RESULT_ERROR);
    721 
    722 	}
    723 
    724 	if (out == NULL)
    725 		return (KORE_RESULT_OK);
    726 
    727 	dom = NULL;
    728 
    729 	LIST_FOREACH(srv, &kore_servers, list) {
    730 		dom = NULL;
    731 
    732 		if (srv->tls == 0)
    733 			continue;
    734 
    735 		TAILQ_FOREACH(dom, &srv->domains, list) {
    736 			if (!strcmp(dom->domain, req->domain))
    737 				break;
    738 		}
    739 
    740 		if (dom != NULL)
    741 			break;
    742 	}
    743 
    744 	if (dom == NULL) {
    745 		kore_log(LOG_WARNING,
    746 		    "got keymgr response for domain that does not exist");
    747 		return (KORE_RESULT_ERROR);
    748 	}
    749 
    750 	*out = dom;
    751 
    752 	return (KORE_RESULT_OK);
    753 }
    754 
    755 void
    756 kore_worker_started(void)
    757 {
    758 	const char	*chroot;
    759 
    760 	if (worker->ps->skip_chroot)
    761 		chroot = "root";
    762 	else
    763 		chroot = "chroot";
    764 
    765 	if (!kore_quiet) {
    766 		kore_log(LOG_NOTICE,
    767 		    "started (#%d %s=%s%s%s)",
    768 		    getpid(), chroot, worker->ps->root,
    769 		    worker->ps->skip_runas ? "" : " user=",
    770 		    worker->ps->skip_runas ? "" : worker->ps->runas);
    771 	}
    772 
    773 	worker->ready = 1;
    774 }
    775 
    776 static void
    777 worker_runtime_configure(void)
    778 {
    779 	struct kore_runtime_call	*rcall;
    780 
    781 	rcall = NULL;
    782 
    783 #if defined(KORE_USE_PYTHON)
    784 	rcall = kore_runtime_getcall(KORE_PYTHON_WORKER_START_HOOK);
    785 #endif
    786 
    787 	if (rcall == NULL)
    788 		rcall = kore_runtime_getcall("kore_worker_configure");
    789 
    790 	if (rcall != NULL) {
    791 		kore_runtime_execute(rcall);
    792 		kore_free(rcall);
    793 	}
    794 }
    795 
    796 static struct kore_runtime_call *
    797 worker_runtime_signal(void)
    798 {
    799 	struct kore_runtime_call	*rcall;
    800 
    801 	rcall = NULL;
    802 
    803 #if defined(KORE_USE_PYTHON)
    804 	rcall = kore_runtime_getcall(KORE_PYTHON_SIGNAL_HOOK);
    805 #endif
    806 
    807 	if (rcall == NULL)
    808 		rcall = kore_runtime_getcall("kore_worker_signal");
    809 
    810 	return (rcall);
    811 }
    812 
    813 static void
    814 worker_runtime_teardown(void)
    815 {
    816 	struct kore_runtime_call	*rcall;
    817 
    818 	rcall = NULL;
    819 
    820 #if defined(KORE_USE_PYTHON)
    821 	rcall = kore_runtime_getcall(KORE_PYTHON_WORKER_STOP_HOOK);
    822 #endif
    823 
    824 	if (rcall == NULL)
    825 		rcall = kore_runtime_getcall("kore_worker_teardown");
    826 
    827 	if (rcall != NULL) {
    828 		kore_runtime_execute(rcall);
    829 		kore_free(rcall);
    830 	}
    831 }
    832 
    833 static void
    834 worker_domain_check(struct kore_domain *dom)
    835 {
    836 	struct stat	st;
    837 
    838 	if (dom->cafile != NULL) {
    839 		if (stat(dom->cafile, &st) == -1)
    840 			fatalx("'%s': %s", dom->cafile, errno_s);
    841 		if (access(dom->cafile, R_OK) == -1)
    842 			fatalx("'%s': not readable", dom->cafile, errno_s);
    843 	}
    844 }
    845 
    846 static void
    847 worker_reaper(pid_t pid, int status)
    848 {
    849 	u_int16_t		idx;
    850 	struct kore_worker	*kw;
    851 	const char		*func;
    852 
    853 #if defined(__linux__)
    854 	if (kore_seccomp_trace(pid, status))
    855 		return;
    856 #endif
    857 
    858 	for (idx = 0; idx < worker_count; idx++) {
    859 		kw = WORKER(idx);
    860 		if (kw->pid != pid)
    861 			continue;
    862 
    863 		kw->msg[0]->evt.flags |= KORE_EVENT_READ;
    864 		net_recv_flush(kw->msg[0]);
    865 
    866 		if (!kore_quiet) {
    867 			kore_log(LOG_NOTICE,
    868 			    "worker %s (%d) exited with status %d",
    869 			    kore_worker_name(kw->id), pid, status);
    870 		}
    871 
    872 		kw->running = 0;
    873 
    874 		if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
    875 			kw->pid = 0;
    876 			break;
    877 		}
    878 
    879 		func = "none";
    880 #if !defined(KORE_NO_HTTP)
    881 		if (kw->active_route != NULL)
    882 			func = kw->active_route->func;
    883 #endif
    884 		kore_log(LOG_NOTICE,
    885 		    "worker %d (pid: %d) (hdlr: %s) gone",
    886 		    kw->id, kw->pid, func);
    887 
    888 #if defined(__linux__)
    889 		if (WIFSIGNALED(status) && WTERMSIG(status) == SIGSYS) {
    890 			kore_log(LOG_NOTICE,
    891 			    "worker %d died from sandbox violation", kw->id);
    892 		}
    893 #endif
    894 
    895 		if (kw->id == KORE_WORKER_KEYMGR ||
    896 		    kw->id == KORE_WORKER_ACME) {
    897 			kore_log(LOG_CRIT,
    898 			    "keymgr or acme process gone, stopping");
    899 			kw->pid = 0;
    900 			kore_quit = 1;
    901 			break;
    902 		}
    903 
    904 		if (kw->pid == accept_lock->current &&
    905 		    worker_no_lock == 0)
    906 			worker_unlock();
    907 
    908 #if !defined(KORE_NO_HTTP)
    909 		if (kw->active_route != NULL) {
    910 			kw->active_route->errors++;
    911 			kore_log(LOG_NOTICE,
    912 			    "hdlr %s has caused %d error(s)",
    913 			    kw->active_route->func,
    914 			    kw->active_route->errors);
    915 		}
    916 #endif
    917 
    918 		if (worker_policy == KORE_WORKER_POLICY_TERMINATE) {
    919 			kw->pid = 0;
    920 			kore_log(LOG_NOTICE,
    921 			    "worker policy is 'terminate', stopping");
    922 			kore_quit = 1;
    923 			break;
    924 		}
    925 
    926 		if (kore_quit == 0) {
    927 			kore_log(LOG_NOTICE, "restarting worker %d", kw->id);
    928 			kw->restarted = 1;
    929 			kore_msg_parent_remove(kw);
    930 
    931 			if (!kore_worker_spawn(idx, kw->id, kw->cpu)) {
    932 				kore_quit = 1;
    933 				kore_log(LOG_ERR, "failed to restart worker");
    934 			} else {
    935 				kore_msg_parent_add(kw);
    936 			}
    937 
    938 			break;
    939 		}
    940 	}
    941 }
    942 
    943 static inline void
    944 worker_acceptlock_release(void)
    945 {
    946 	if (worker_count == WORKER_SOLO_COUNT || worker_no_lock == 1)
    947 		return;
    948 
    949 	if (worker->has_lock != 1)
    950 		return;
    951 
    952 	if (worker_active_connections < worker_max_connections) {
    953 #if !defined(KORE_NO_HTTP)
    954 		if (http_request_count < http_request_limit)
    955 			return;
    956 #else
    957 		return;
    958 #endif
    959 	}
    960 
    961 #if defined(WORKER_DEBUG)
    962 	kore_log(LOG_DEBUG, "worker busy, releasing lock");
    963 #endif
    964 
    965 	worker_unlock();
    966 	worker->has_lock = 0;
    967 
    968 	kore_msg_send(KORE_MSG_WORKER_ALL, KORE_MSG_ACCEPT_AVAILABLE, NULL, 0);
    969 }
    970 
    971 static inline int
    972 worker_acceptlock_obtain(void)
    973 {
    974 	int		r;
    975 
    976 	if (worker->has_lock == 1)
    977 		return (1);
    978 
    979 	if (worker_count == WORKER_SOLO_COUNT || worker_no_lock == 1) {
    980 		worker->has_lock = 1;
    981 		return (1);
    982 	}
    983 
    984 	if (worker_active_connections >= worker_max_connections)
    985 		return (0);
    986 
    987 #if !defined(KORE_NO_HTTP)
    988 	if (http_request_count >= http_request_limit)
    989 		return (0);
    990 #endif
    991 
    992 	r = 0;
    993 	if (worker_trylock()) {
    994 		r = 1;
    995 		worker->has_lock = 1;
    996 #if defined(WORKER_DEBUG)
    997 		kore_log(LOG_DEBUG, "got lock");
    998 #endif
    999 	}
   1000 
   1001 	return (r);
   1002 }
   1003 
   1004 static int
   1005 worker_trylock(void)
   1006 {
   1007 	if (!__sync_bool_compare_and_swap(&(accept_lock->lock), 0, 1))
   1008 		return (0);
   1009 
   1010 	accept_lock->current = worker->pid;
   1011 
   1012 	return (1);
   1013 }
   1014 
   1015 static void
   1016 worker_unlock(void)
   1017 {
   1018 	accept_lock->current = 0;
   1019 	if (!__sync_bool_compare_and_swap(&(accept_lock->lock), 1, 0))
   1020 		kore_log(LOG_NOTICE, "worker_unlock(): wasn't locked");
   1021 }
   1022 
   1023 static void
   1024 worker_accept_avail(struct kore_msg *msg, const void *data)
   1025 {
   1026 	accept_avail = 1;
   1027 }
   1028 
   1029 static void
   1030 worker_entropy_recv(struct kore_msg *msg, const void *data)
   1031 {
   1032 	if (msg->length != 1024) {
   1033 		kore_log(LOG_WARNING,
   1034 		    "invalid entropy response (got:%zu - wanted:1024)",
   1035 		    msg->length);
   1036 	}
   1037 
   1038 	kore_tls_seed(data, msg->length);
   1039 }
   1040 
   1041 static void
   1042 worker_keymgr_response(struct kore_msg *msg, const void *data)
   1043 {
   1044 	struct kore_domain		*dom;
   1045 	const struct kore_x509_msg	*req;
   1046 
   1047 	if (!kore_worker_keymgr_response_verify(msg, data, &dom))
   1048 		return;
   1049 
   1050 	req = (const struct kore_x509_msg *)data;
   1051 
   1052 	switch (msg->id) {
   1053 	case KORE_MSG_CERTIFICATE:
   1054 		kore_tls_domain_setup(dom, KORE_PEM_CERT_CHAIN,
   1055 		    req->data, req->data_len);
   1056 		break;
   1057 	case KORE_MSG_CRL:
   1058 		kore_tls_domain_crl(dom, req->data, req->data_len);
   1059 		break;
   1060 #if defined(KORE_USE_ACME)
   1061 	case KORE_ACME_CHALLENGE_SET_CERT:
   1062 		if (dom->tls_ctx == NULL) {
   1063 			kore_tls_domain_setup(dom, KORE_DER_CERT_DATA,
   1064 			    req->data, req->data_len);
   1065 		}
   1066 
   1067 		kore_free(dom->acme_cert);
   1068 		dom->acme_cert_len = req->data_len;
   1069 		dom->acme_cert = kore_calloc(1, req->data_len);
   1070 		memcpy(dom->acme_cert, req->data, req->data_len);
   1071 
   1072 		kore_log(LOG_NOTICE, "[%s] tls-alpn-01 challenge active",
   1073 		    dom->domain);
   1074 		dom->acme_challenge = 1;
   1075 		break;
   1076 	case KORE_ACME_CHALLENGE_CLEAR_CERT:
   1077 		dom->acme_cert_len = 0;
   1078 		dom->acme_challenge = 0;
   1079 
   1080 		kore_free(dom->acme_cert);
   1081 		dom->acme_cert = NULL;
   1082 
   1083 		kore_log(LOG_NOTICE, "[%s] tls-alpn-01 challenge disabled",
   1084 		    dom->domain);
   1085 		break;
   1086 #endif
   1087 	default:
   1088 		kore_log(LOG_WARNING, "unknown keymgr request %u", msg->id);
   1089 		break;
   1090 	}
   1091 }