Blob


1 /*
2 * Copyright (c) 2023 Omar Polo <op@omarpolo.com>
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 */
17 #include "gmid.h"
19 #include <sys/stat.h>
21 #include <fcntl.h>
22 #include <limits.h>
23 #include <string.h>
25 #include <openssl/pem.h>
27 #include "log.h"
28 #include "proc.h"
30 struct conf *
31 config_new(void)
32 {
33 struct conf *conf;
35 conf = xcalloc(1, sizeof(*conf));
37 TAILQ_INIT(&conf->fcgi);
38 TAILQ_INIT(&conf->hosts);
39 TAILQ_INIT(&conf->pkis);
41 conf->port = 1965;
42 conf->ipv6 = 0;
43 conf->protos = TLS_PROTOCOL_TLSv1_2 | TLS_PROTOCOL_TLSv1_3;
45 init_mime(&conf->mime);
47 conf->prefork = 3;
49 #ifdef __OpenBSD__
50 conf->use_privsep_crypto = 1;
51 #endif
53 conf->sock4 = -1;
54 conf->sock6 = -1;
56 return conf;
57 }
59 void
60 config_purge(struct conf *conf)
61 {
62 struct privsep *ps;
63 struct fcgi *f, *tf;
64 struct vhost *h, *th;
65 struct location *l, *tl;
66 struct proxy *p, *tp;
67 struct envlist *e, *te;
68 struct alist *a, *ta;
69 struct pki *pki, *tpki;
70 int use_privsep_crypto;
72 ps = conf->ps;
73 use_privsep_crypto = conf->use_privsep_crypto;
75 if (conf->sock4 != -1) {
76 event_del(&conf->evsock4);
77 close(conf->sock4);
78 }
80 if (conf->sock6 != -1) {
81 event_del(&conf->evsock6);
82 close(conf->sock6);
83 }
85 free_mime(&conf->mime);
86 TAILQ_FOREACH_SAFE(f, &conf->fcgi, fcgi, tf) {
87 TAILQ_REMOVE(&conf->fcgi, f, fcgi);
88 free(f);
89 }
91 TAILQ_FOREACH_SAFE(h, &conf->hosts, vhosts, th) {
92 free(h->cert_path);
93 free(h->key_path);
94 free(h->ocsp_path);
95 free(h->cert);
96 free(h->key);
97 free(h->ocsp);
99 TAILQ_FOREACH_SAFE(l, &h->locations, locations, tl) {
100 TAILQ_REMOVE(&h->locations, l, locations);
102 if (l->dirfd != -1)
103 close(l->dirfd);
105 free(l->reqca_path);
106 X509_STORE_free(l->reqca);
107 free(l);
110 TAILQ_FOREACH_SAFE(e, &h->params, envs, te) {
111 TAILQ_REMOVE(&h->params, e, envs);
112 free(e);
115 TAILQ_FOREACH_SAFE(a, &h->aliases, aliases, ta) {
116 TAILQ_REMOVE(&h->aliases, a, aliases);
117 free(a);
120 TAILQ_FOREACH_SAFE(p, &h->proxies, proxies, tp) {
121 TAILQ_REMOVE(&h->proxies, p, proxies);
122 free(p->cert_path);
123 free(p->cert);
124 free(p->key_path);
125 free(p->key);
126 free(p->reqca_path);
127 X509_STORE_free(p->reqca);
128 free(p);
131 TAILQ_REMOVE(&conf->hosts, h, vhosts);
132 free(h);
135 TAILQ_FOREACH_SAFE(pki, &conf->pkis, pkis, tpki) {
136 TAILQ_REMOVE(&conf->pkis, pki, pkis);
137 free(pki->hash);
138 EVP_PKEY_free(pki->pkey);
139 free(pki);
142 memset(conf, 0, sizeof(*conf));
144 conf->ps = ps;
145 conf->use_privsep_crypto = use_privsep_crypto;
146 conf->sock4 = conf->sock6 = -1;
147 conf->protos = TLS_PROTOCOL_TLSv1_2 | TLS_PROTOCOL_TLSv1_3;
148 init_mime(&conf->mime);
149 TAILQ_INIT(&conf->fcgi);
150 TAILQ_INIT(&conf->hosts);
151 TAILQ_INIT(&conf->pkis);
154 static int
155 config_send_file(struct privsep *ps, enum privsep_procid id, int type,
156 int fd, void *data, size_t l)
158 int n, m, d;
160 n = -1;
161 proc_range(ps, id, &n, &m);
162 for (n = 0; n < m; ++n) {
163 d = -1;
164 if (fd != -1 && (d = dup(fd)) == -1)
165 fatal("dup %d", fd);
166 if (proc_compose_imsg(ps, id, n, type, -1, d, data, l)
167 == -1)
168 return -1;
171 if (fd != -1)
172 close(fd);
173 return 0;
176 static int
177 config_open_send(struct privsep *ps, enum privsep_procid id, int type,
178 const char *path)
180 int fd;
182 log_debug("sending %s", path);
184 if ((fd = open(path, O_RDONLY)) == -1)
185 fatal("can't open %s", path);
187 return config_send_file(ps, id, type, fd, NULL, 0);
190 static int
191 config_send_kp(struct privsep *ps, int cert_type, int key_type,
192 const char *cert, const char *key)
194 struct conf *conf = ps->ps_env;
195 int fd, d, key_target;
197 log_debug("sending %s", cert);
198 if ((fd = open(cert, O_RDONLY)) == -1)
199 fatal("can't open %s", cert);
200 if ((d = dup(fd)) == -1)
201 fatal("fd");
203 if (config_send_file(ps, PROC_SERVER, cert_type, fd, NULL, 0) == -1) {
204 close(d);
205 return -1;
207 if (conf->use_privsep_crypto &&
208 config_send_file(ps, PROC_CRYPTO, cert_type, d, NULL, 0) == -1)
209 return -1;
211 key_target = PROC_CRYPTO;
212 if (!conf->use_privsep_crypto)
213 key_target = PROC_SERVER;
215 if (config_open_send(ps, key_target, key_type, key) == -1)
216 return -1;
218 if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1)
219 return -1;
220 if (proc_flush_imsg(ps, PROC_CRYPTO, -1) == -1)
221 return -1;
222 return 0;
225 static int
226 make_socket(int port, int family)
228 int sock, v;
229 struct sockaddr_in addr4;
230 struct sockaddr_in6 addr6;
231 struct sockaddr *addr;
232 socklen_t len;
234 switch (family) {
235 case AF_INET:
236 memset(&addr4, 0, sizeof(addr4));
237 addr4.sin_family = family;
238 addr4.sin_port = htons(port);
239 addr4.sin_addr.s_addr = INADDR_ANY;
240 addr = (struct sockaddr*)&addr4;
241 len = sizeof(addr4);
242 break;
244 case AF_INET6:
245 memset(&addr6, 0, sizeof(addr6));
246 addr6.sin6_family = AF_INET6;
247 addr6.sin6_port = htons(port);
248 addr6.sin6_addr = in6addr_any;
249 addr = (struct sockaddr*)&addr6;
250 len = sizeof(addr6);
251 break;
253 default:
254 /* unreachable */
255 abort();
258 if ((sock = socket(family, SOCK_STREAM, 0)) == -1)
259 fatal("socket");
261 v = 1;
262 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v)) == -1)
263 fatal("setsockopt(SO_REUSEADDR)");
265 v = 1;
266 if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &v, sizeof(v)) == -1)
267 fatal("setsockopt(SO_REUSEPORT)");
269 mark_nonblock(sock);
271 if (bind(sock, addr, len) == -1)
272 fatal("bind");
274 if (listen(sock, 16) == -1)
275 fatal("listen");
277 return sock;
280 static int
281 config_send_socks(struct conf *conf)
283 struct privsep *ps = conf->ps;
284 int sock;
286 if ((sock = make_socket(conf->port, AF_INET)) == -1)
287 return -1;
289 if (config_send_file(ps, PROC_SERVER, IMSG_RECONF_SOCK4, sock,
290 NULL, 0) == -1)
291 return -1;
293 if (!conf->ipv6)
294 return 0;
296 if ((sock = make_socket(conf->port, AF_INET6)) == -1)
297 return -1;
299 if (config_send_file(ps, PROC_SERVER, IMSG_RECONF_SOCK6, sock,
300 NULL, 0) == -1)
301 return -1;
303 return 0;
306 int
307 config_send(struct conf *conf)
309 struct privsep *ps = conf->ps;
310 struct etm *m;
311 struct fcgi *fcgi;
312 struct vhost *h;
313 struct location *l;
314 struct proxy *p;
315 struct envlist *e;
316 struct alist *a;
317 size_t i;
319 for (i = 0; i < conf->mime.len; ++i) {
320 m = &conf->mime.t[i];
321 if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_MIME,
322 m, sizeof(*m)) == -1)
323 return -1;
326 if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_PROTOS,
327 &conf->protos, sizeof(conf->protos)) == -1)
328 return -1;
330 if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_PORT,
331 &conf->port, sizeof(conf->port)) == -1)
332 return -1;
334 if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1)
335 return -1;
337 if (config_send_socks(conf) == -1)
338 return -1;
340 if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1)
341 return -1;
343 TAILQ_FOREACH(fcgi, &conf->fcgi, fcgi) {
344 log_debug("sending fastcgi %s", fcgi->path);
345 if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_FCGI,
346 fcgi, sizeof(*fcgi)) == -1)
347 return -1;
350 TAILQ_FOREACH(h, &conf->hosts, vhosts) {
351 struct vhost vcopy;
353 memcpy(&vcopy, h, sizeof(vcopy));
354 vcopy.cert_path = NULL;
355 vcopy.key_path = NULL;
356 vcopy.ocsp_path = NULL;
358 log_debug("sending host %s", h->domain);
360 if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_HOST,
361 &vcopy, sizeof(vcopy)) == -1)
362 return -1;
364 if (config_send_kp(ps, IMSG_RECONF_CERT, IMSG_RECONF_KEY,
365 h->cert_path, h->key_path) == -1)
366 return -1;
368 if (h->ocsp_path != NULL) {
369 if (config_open_send(ps, PROC_SERVER, IMSG_RECONF_OCSP,
370 h->ocsp_path) == -1)
371 return -1;
372 if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1)
373 return -1;
376 TAILQ_FOREACH(l, &h->locations, locations) {
377 struct location lcopy;
378 int fd = -1;
380 memcpy(&lcopy, l, sizeof(lcopy));
381 lcopy.reqca_path = NULL;
382 lcopy.reqca = NULL;
383 lcopy.dirfd = -1;
384 memset(&lcopy.locations, 0, sizeof(lcopy.locations));
386 if (l->reqca_path != NULL &&
387 (fd = open(l->reqca_path, O_RDONLY)) == -1)
388 fatal("can't open %s", l->reqca_path);
390 if (config_send_file(ps, PROC_SERVER, IMSG_RECONF_LOC,
391 fd, &lcopy, sizeof(lcopy)) == -1)
392 return -1;
395 if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1)
396 return -1;
398 TAILQ_FOREACH(e, &h->params, envs) {
399 if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_ENV,
400 e, sizeof(*e)) == -1)
401 return -1;
404 if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1)
405 return -1;
407 TAILQ_FOREACH(a, &h->aliases, aliases) {
408 if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_ALIAS,
409 a, sizeof(*a)) == -1)
410 return -1;
413 if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1)
414 return -1;
416 TAILQ_FOREACH(p, &h->proxies, proxies) {
417 struct proxy pcopy;
418 int fd = -1;
420 memcpy(&pcopy, p, sizeof(pcopy));
421 pcopy.cert_path = NULL;
422 pcopy.cert = NULL;
423 pcopy.certlen = 0;
424 pcopy.key_path = NULL;
425 pcopy.key = NULL;
426 pcopy.keylen = 0;
427 pcopy.reqca_path = NULL;
428 pcopy.reqca = NULL;
430 if (p->reqca_path != NULL) {
431 fd = open(p->reqca_path, O_RDONLY);
432 if (fd == -1)
433 fatal("can't open %s", p->reqca_path);
436 if (config_send_file(ps, PROC_SERVER, IMSG_RECONF_PROXY,
437 fd, &pcopy, sizeof(pcopy)) == -1)
438 return -1;
440 if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1)
441 return -1;
443 if (p->cert_path == NULL || p->key_path == NULL)
444 continue;
446 if (config_open_send(ps, PROC_SERVER,
447 IMSG_RECONF_PROXY_CERT, p->cert_path) == -1 ||
448 config_open_send(ps, PROC_SERVER,
449 IMSG_RECONF_PROXY_KEY, p->key_path) == -1)
450 return -1;
452 if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1)
453 return -1;
456 if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1)
457 return -1;
460 return 0;
463 static int
464 load_file(int fd, uint8_t **data, size_t *len)
466 struct stat sb;
467 ssize_t r;
469 if (fstat(fd, &sb) == -1)
470 fatal("fstat");
472 if (sb.st_size < 0 /* || sb.st_size > SIZE_MAX */) {
473 log_warnx("file too large");
474 close(fd);
475 return -1;
477 *len = sb.st_size;
479 if ((*data = malloc(*len)) == NULL)
480 fatal("malloc");
482 r = pread(fd, *data, *len, 0);
483 if (r == -1 || (size_t)r != *len) {
484 log_warn("read failed");
485 close(fd);
486 free(*data);
487 return -1;
490 close(fd);
491 return 0;
494 static int
495 config_crypto_recv_kp(struct conf *conf, struct imsg *imsg)
497 static struct pki *pki;
498 uint8_t *d;
499 size_t len;
501 /* XXX: check for duplicates */
503 if (imsg->fd == -1)
504 fatalx("no fd for imsg %d", imsg->hdr.type);
506 switch (imsg->hdr.type) {
507 case IMSG_RECONF_CERT:
508 if (pki != NULL)
509 fatalx("imsg in wrong order; pki is not NULL");
510 if ((pki = calloc(1, sizeof(*pki))) == NULL)
511 fatal("calloc");
512 if (load_file(imsg->fd, &d, &len) == -1)
513 fatalx("can't load file");
514 if ((pki->hash = ssl_pubkey_hash(d, len)) == NULL)
515 fatalx("failed to compute cert hash");
516 free(d);
517 TAILQ_INSERT_TAIL(&conf->pkis, pki, pkis);
518 break;
520 case IMSG_RECONF_KEY:
521 if (pki == NULL)
522 fatalx("got key without cert beforehand %d",
523 imsg->hdr.type);
524 if (load_file(imsg->fd, &d, &len) == -1)
525 fatalx("failed to load private key");
526 if ((pki->pkey = ssl_load_pkey(d, len)) == NULL)
527 fatalx("failed load private key");
528 free(d);
529 pki = NULL;
530 break;
532 default:
533 return -1;
536 return 0;
539 int
540 config_recv(struct conf *conf, struct imsg *imsg)
542 static struct vhost *h;
543 static struct proxy *p;
544 struct privsep *ps = conf->ps;
545 struct etm m;
546 struct fcgi *fcgi;
547 struct vhost *vh, vht;
548 struct location *loc;
549 struct envlist *env;
550 struct alist *alias;
551 struct proxy *proxy;
552 uint8_t *d;
553 size_t len, datalen;
555 datalen = IMSG_DATA_SIZE(imsg);
557 switch (imsg->hdr.type) {
558 case IMSG_RECONF_START:
559 config_purge(conf);
560 h = NULL;
561 p = NULL;
562 break;
564 case IMSG_RECONF_MIME:
565 IMSG_SIZE_CHECK(imsg, &m);
566 memcpy(&m, imsg->data, datalen);
567 if (m.mime[sizeof(m.mime) - 1] != '\0' ||
568 m.ext[sizeof(m.ext) - 1] != '\0')
569 fatal("received corrupted IMSG_RECONF_MIME");
570 if (add_mime(&conf->mime, m.mime, m.ext) == -1)
571 fatal("failed to add mime mapping %s -> %s",
572 m.mime, m.ext);
573 break;
575 case IMSG_RECONF_PROTOS:
576 IMSG_SIZE_CHECK(imsg, &conf->protos);
577 memcpy(&conf->protos, imsg->data, datalen);
578 break;
580 case IMSG_RECONF_PORT:
581 IMSG_SIZE_CHECK(imsg, &conf->port);
582 memcpy(&conf->port, imsg->data, datalen);
583 break;
585 case IMSG_RECONF_SOCK4:
586 if (conf->sock4 != -1)
587 fatalx("socket ipv4 already recv'd");
588 if (imsg->fd == -1)
589 fatalx("missing socket for IMSG_RECONF_SOCK4");
590 conf->sock4 = imsg->fd;
591 event_set(&conf->evsock4, conf->sock4, EV_READ|EV_PERSIST,
592 do_accept, conf);
593 break;
595 case IMSG_RECONF_SOCK6:
596 if (conf->sock6 != -1)
597 fatalx("socket ipv6 already recv'd");
598 if (imsg->fd == -1)
599 fatalx("missing socket for IMSG_RECONF_SOCK6");
600 conf->sock6 = imsg->fd;
601 event_set(&conf->evsock6, conf->sock6, EV_READ|EV_PERSIST,
602 do_accept, conf);
603 break;
605 case IMSG_RECONF_FCGI:
606 IMSG_SIZE_CHECK(imsg, fcgi);
607 fcgi = xcalloc(1, sizeof(*fcgi));
608 memcpy(fcgi, imsg->data, datalen);
609 log_debug("received fcgi %s", fcgi->path);
610 TAILQ_INSERT_TAIL(&conf->fcgi, fcgi, fcgi);
611 break;
613 case IMSG_RECONF_HOST:
614 IMSG_SIZE_CHECK(imsg, &vht);
615 memcpy(&vht, imsg->data, datalen);
616 vh = new_vhost();
617 strlcpy(vh->domain, vht.domain, sizeof(vh->domain));
618 h = vh;
619 TAILQ_INSERT_TAIL(&conf->hosts, h, vhosts);
621 /* reset proxy */
622 p = NULL;
623 break;
625 case IMSG_RECONF_CERT:
626 log_debug("receiving cert");
627 if (privsep_process == PROC_CRYPTO)
628 return config_crypto_recv_kp(conf, imsg);
629 if (h == NULL)
630 fatalx("recv'd cert without host");
631 if (h->cert != NULL)
632 fatalx("cert already received");
633 if (imsg->fd == -1)
634 fatalx("no fd for IMSG_RECONF_CERT");
635 if (load_file(imsg->fd, &h->cert, &h->certlen) == -1)
636 fatalx("failed to load cert for %s",
637 h->domain);
638 break;
640 case IMSG_RECONF_KEY:
641 log_debug("receiving key");
642 if (privsep_process == PROC_CRYPTO)
643 return config_crypto_recv_kp(conf, imsg);
644 if (h == NULL)
645 fatalx("recv'd key without host");
646 if (h->key != NULL)
647 fatalx("key already received");
648 if (imsg->fd == -1)
649 fatalx("no fd for IMSG_RECONF_KEY");
650 if (load_file(imsg->fd, &h->key, &h->keylen) == -1)
651 fatalx("failed to load key for %s",
652 h->domain);
653 break;
655 case IMSG_RECONF_OCSP:
656 log_debug("receiving ocsp");
657 if (h == NULL)
658 fatalx("recv'd ocsp without host");
659 if (h->ocsp != NULL)
660 fatalx("ocsp already received");
661 if (imsg->fd == -1)
662 fatalx("no fd for IMSG_RECONF_OCSP");
663 if (load_file(imsg->fd, &h->ocsp, &h->ocsplen) == -1)
664 fatalx("failed to load ocsp for %s",
665 h->domain);
666 break;
668 case IMSG_RECONF_LOC:
669 if (h == NULL)
670 fatalx("recv'd location without host");
671 IMSG_SIZE_CHECK(imsg, loc);
672 loc = xcalloc(1, sizeof(*loc));
673 memcpy(loc, imsg->data, datalen);
675 if (imsg->fd != -1) {
676 if (load_file(imsg->fd, &d, &len) == -1)
677 fatal("load_file");
678 loc->reqca = load_ca(d, len);
679 if (loc->reqca == NULL)
680 fatalx("failed to load CA");
681 free(d);
684 TAILQ_INSERT_TAIL(&h->locations, loc, locations);
685 break;
687 case IMSG_RECONF_ENV:
688 if (h == NULL)
689 fatalx("recv'd env without host");
690 IMSG_SIZE_CHECK(imsg, env);
691 env = xcalloc(1, sizeof(*env));
692 memcpy(env, imsg->data, datalen);
693 TAILQ_INSERT_TAIL(&h->params, env, envs);
694 break;
696 case IMSG_RECONF_ALIAS:
697 if (h == NULL)
698 fatalx("recv'd alias without host");
699 IMSG_SIZE_CHECK(imsg, alias);
700 alias = xcalloc(1, sizeof(*alias));
701 memcpy(alias, imsg->data, datalen);
702 TAILQ_INSERT_TAIL(&h->aliases, alias, aliases);
703 break;
705 case IMSG_RECONF_PROXY:
706 log_debug("receiving proxy");
707 if (h == NULL)
708 fatalx("recv'd proxy without host");
709 IMSG_SIZE_CHECK(imsg, proxy);
710 proxy = xcalloc(1, sizeof(*proxy));
711 memcpy(proxy, imsg->data, datalen);
713 if (imsg->fd != -1) {
714 if (load_file(imsg->fd, &d, &len) == -1)
715 fatal("load_file");
716 proxy->reqca = load_ca(d, len);
717 if (proxy->reqca == NULL)
718 fatal("failed to load CA");
719 free(d);
722 TAILQ_INSERT_TAIL(&h->proxies, proxy, proxies);
723 p = proxy;
724 break;
726 case IMSG_RECONF_PROXY_CERT:
727 log_debug("receiving proxy cert");
728 if (p == NULL)
729 fatalx("recv'd proxy cert without proxy");
730 if (p->cert != NULL)
731 fatalx("proxy cert already received");
732 if (imsg->fd == -1)
733 fatalx("no fd for IMSG_RECONF_PROXY_CERT");
734 if (load_file(imsg->fd, &p->cert, &p->certlen) == -1)
735 fatalx("failed to load cert for proxy %s of %s",
736 p->host, h->domain);
737 break;
739 case IMSG_RECONF_PROXY_KEY:
740 log_debug("receiving proxy key");
741 if (p == NULL)
742 fatalx("recv'd proxy key without proxy");
743 if (p->key != NULL)
744 fatalx("proxy key already received");
745 if (imsg->fd == -1)
746 fatalx("no fd for IMSG_RECONF_PROXY_KEY");
747 if (load_file(imsg->fd, &p->key, &p->keylen) == -1)
748 fatalx("failed to load key for proxy %s of %s",
749 p->host, h->domain);
750 break;
752 case IMSG_RECONF_END:
753 if (proc_compose(ps, PROC_PARENT, IMSG_RECONF_DONE,
754 NULL, 0) == -1)
755 return -1;
756 break;
758 default:
759 return -1;
762 return 0;