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 "log.h"
26 #include "proc.h"
28 void
29 config_init(void)
30 {
31 memset(&conf, 0, sizeof(conf));
33 TAILQ_INIT(&hosts);
35 TAILQ_INIT(&conf.fcgi);
37 conf.port = 1965;
38 conf.ipv6 = 0;
39 conf.protos = TLS_PROTOCOL_TLSv1_2 | TLS_PROTOCOL_TLSv1_3;
41 init_mime(&conf.mime);
43 conf.prefork = 3;
45 conf.sock4 = -1;
46 conf.sock6 = -1;
47 }
49 void
50 config_free(void)
51 {
52 struct privsep *ps;
53 struct fcgi *f, *tf;
54 struct vhost *h, *th;
55 struct location *l, *tl;
56 struct proxy *p, *tp;
57 struct envlist *e, *te;
58 struct alist *a, *ta;
60 ps = conf.ps;
62 if (conf.sock4 != -1) {
63 event_del(&conf.evsock4);
64 close(conf.sock4);
65 }
67 if (conf.sock6 != -1) {
68 event_del(&conf.evsock6);
69 close(conf.sock6);
70 }
72 free_mime(&conf.mime);
73 TAILQ_FOREACH_SAFE(f, &conf.fcgi, fcgi, tf) {
74 TAILQ_REMOVE(&conf.fcgi, f, fcgi);
75 free(f);
76 }
77 memset(&conf, 0, sizeof(conf));
79 conf.ps = ps;
80 conf.sock4 = conf.sock6 = -1;
81 conf.protos = TLS_PROTOCOL_TLSv1_2 | TLS_PROTOCOL_TLSv1_3;
82 init_mime(&conf.mime);
83 TAILQ_INIT(&conf.fcgi);
85 TAILQ_FOREACH_SAFE(h, &hosts, vhosts, th) {
86 free(h->cert_path);
87 free(h->key_path);
88 free(h->ocsp_path);
89 free(h->cert);
90 free(h->key);
91 free(h->ocsp);
93 TAILQ_FOREACH_SAFE(l, &h->locations, locations, tl) {
94 TAILQ_REMOVE(&h->locations, l, locations);
96 if (l->dirfd != -1)
97 close(l->dirfd);
99 free(l->reqca_path);
100 X509_STORE_free(l->reqca);
101 free(l);
104 TAILQ_FOREACH_SAFE(e, &h->params, envs, te) {
105 TAILQ_REMOVE(&h->params, e, envs);
106 free(e);
109 TAILQ_FOREACH_SAFE(a, &h->aliases, aliases, ta) {
110 TAILQ_REMOVE(&h->aliases, a, aliases);
111 free(a);
114 TAILQ_FOREACH_SAFE(p, &h->proxies, proxies, tp) {
115 TAILQ_REMOVE(&h->proxies, p, proxies);
116 free(p->cert_path);
117 free(p->cert);
118 free(p->key_path);
119 free(p->key);
120 free(p->reqca_path);
121 X509_STORE_free(p->reqca);
122 free(p);
125 TAILQ_REMOVE(&hosts, h, vhosts);
126 free(h);
130 static int
131 config_send_file(struct privsep *ps, int type, int fd, void *data, size_t l)
133 int n, m, id, d;
135 id = PROC_SERVER;
136 n = -1;
137 proc_range(ps, id, &n, &m);
138 for (n = 0; n < m; ++n) {
139 d = -1;
140 if (fd != -1 && (d = dup(fd)) == -1)
141 fatal("dup %d", fd);
142 if (proc_compose_imsg(ps, id, n, type, -1, d, data, l)
143 == -1)
144 return -1;
147 if (fd != -1)
148 close(fd);
149 return 0;
152 static int
153 config_open_send(struct privsep *ps, int type, const char *path)
155 int fd;
157 log_debug("sending %s", path);
159 if ((fd = open(path, O_RDONLY)) == -1)
160 fatal("can't open %s", path);
162 return config_send_file(ps, type, fd, NULL, 0);
165 static int
166 make_socket(int port, int family)
168 int sock, v;
169 struct sockaddr_in addr4;
170 struct sockaddr_in6 addr6;
171 struct sockaddr *addr;
172 socklen_t len;
174 switch (family) {
175 case AF_INET:
176 memset(&addr4, 0, sizeof(addr4));
177 addr4.sin_family = family;
178 addr4.sin_port = htons(port);
179 addr4.sin_addr.s_addr = INADDR_ANY;
180 addr = (struct sockaddr*)&addr4;
181 len = sizeof(addr4);
182 break;
184 case AF_INET6:
185 memset(&addr6, 0, sizeof(addr6));
186 addr6.sin6_family = AF_INET6;
187 addr6.sin6_port = htons(port);
188 addr6.sin6_addr = in6addr_any;
189 addr = (struct sockaddr*)&addr6;
190 len = sizeof(addr6);
191 break;
193 default:
194 /* unreachable */
195 abort();
198 if ((sock = socket(family, SOCK_STREAM, 0)) == -1)
199 fatal("socket");
201 v = 1;
202 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v)) == -1)
203 fatal("setsockopt(SO_REUSEADDR)");
205 v = 1;
206 if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &v, sizeof(v)) == -1)
207 fatal("setsockopt(SO_REUSEPORT)");
209 mark_nonblock(sock);
211 if (bind(sock, addr, len) == -1)
212 fatal("bind");
214 if (listen(sock, 16) == -1)
215 fatal("listen");
217 return sock;
220 static int
221 config_send_socks(struct conf *conf)
223 struct privsep *ps = conf->ps;
224 int sock;
226 if ((sock = make_socket(conf->port, AF_INET)) == -1)
227 return -1;
229 if (config_send_file(ps, IMSG_RECONF_SOCK4, sock, NULL, 0) == -1)
230 return -1;
232 if (!conf->ipv6)
233 return 0;
235 if ((sock = make_socket(conf->port, AF_INET6)) == -1)
236 return -1;
238 if (config_send_file(ps, IMSG_RECONF_SOCK6, sock, NULL, 0) == -1)
239 return -1;
241 return 0;
244 int
245 config_send(struct conf *conf, struct vhosthead *hosts)
247 struct privsep *ps = conf->ps;
248 struct etm *m;
249 struct fcgi *fcgi;
250 struct vhost *h;
251 struct location *l;
252 struct proxy *p;
253 struct envlist *e;
254 struct alist *a;
255 size_t i;
256 int fd;
258 for (i = 0; i < conf->mime.len; ++i) {
259 m = &conf->mime.t[i];
260 if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_MIME,
261 m, sizeof(*m)) == -1)
262 return -1;
265 if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_PROTOS,
266 &conf->protos, sizeof(conf->protos)) == -1)
267 return -1;
269 if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_PORT,
270 &conf->port, sizeof(conf->port)) == -1)
271 return -1;
273 if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1)
274 return -1;
276 if (config_send_socks(conf) == -1)
277 return -1;
279 if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1)
280 return -1;
282 TAILQ_FOREACH(fcgi, &conf->fcgi, fcgi) {
283 log_debug("sending fastcgi %s", fcgi->path);
284 if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_FCGI,
285 fcgi, sizeof(*fcgi)) == -1)
286 return -1;
289 TAILQ_FOREACH(h, hosts, vhosts) {
290 struct vhost vcopy;
292 memcpy(&vcopy, h, sizeof(vcopy));
293 vcopy.cert_path = NULL;
294 vcopy.key_path = NULL;
295 vcopy.ocsp_path = NULL;
297 log_debug("sending host %s", h->domain);
299 if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_HOST,
300 &vcopy, sizeof(vcopy)) == -1)
301 return -1;
303 log_debug("sending certificate %s", h->cert_path);
304 if ((fd = open(h->cert_path, O_RDONLY)) == -1)
305 fatal("can't open %s", h->cert_path);
306 if (config_send_file(ps, IMSG_RECONF_CERT, fd, NULL, 0) == -1)
307 return -1;
309 log_debug("sending key %s", h->key_path);
310 if ((fd = open(h->key_path, O_RDONLY)) == -1)
311 fatal("can't open %s", h->key_path);
312 if (config_send_file(ps, IMSG_RECONF_KEY, fd, NULL, 0) == -1)
313 return -1;
315 if (h->ocsp_path != NULL) {
316 log_debug("sending ocsp %s", h->ocsp_path);
317 if ((fd = open(h->ocsp_path, O_RDONLY)) == -1)
318 fatal("can't open %s", h->ocsp_path);
319 if (config_send_file(ps, IMSG_RECONF_OCSP, fd,
320 NULL, 0) == -1)
321 return -1;
324 TAILQ_FOREACH(l, &h->locations, locations) {
325 struct location lcopy;
326 int fd = -1;
328 memcpy(&lcopy, l, sizeof(lcopy));
329 lcopy.reqca_path = NULL;
330 lcopy.reqca = NULL;
331 lcopy.dirfd = -1;
332 memset(&lcopy.locations, 0, sizeof(lcopy.locations));
334 if (l->reqca_path != NULL &&
335 (fd = open(l->reqca_path, O_RDONLY)) == -1)
336 fatal("can't open %s", l->reqca_path);
338 if (config_send_file(ps, IMSG_RECONF_LOC, fd,
339 &lcopy, sizeof(lcopy)) == -1)
340 return -1;
343 if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1)
344 return -1;
346 TAILQ_FOREACH(e, &h->params, envs) {
347 if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_ENV,
348 e, sizeof(*e)) == -1)
349 return -1;
352 if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1)
353 return -1;
355 TAILQ_FOREACH(a, &h->aliases, aliases) {
356 if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_ALIAS,
357 a, sizeof(*a)) == -1)
358 return -1;
361 if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1)
362 return -1;
364 TAILQ_FOREACH(p, &h->proxies, proxies) {
365 struct proxy pcopy;
366 int fd = -1;
368 memcpy(&pcopy, p, sizeof(pcopy));
369 pcopy.cert_path = NULL;
370 pcopy.cert = NULL;
371 pcopy.certlen = 0;
372 pcopy.key_path = NULL;
373 pcopy.key = NULL;
374 pcopy.keylen = 0;
375 pcopy.reqca_path = NULL;
376 pcopy.reqca = NULL;
378 if (p->reqca_path != NULL) {
379 fd = open(p->reqca_path, O_RDONLY);
380 if (fd == -1)
381 fatal("can't open %s", p->reqca_path);
384 if (config_send_file(ps, IMSG_RECONF_PROXY, fd,
385 &pcopy, sizeof(pcopy)) == -1)
386 return -1;
388 if (p->cert_path != NULL &&
389 config_open_send(ps, IMSG_RECONF_PROXY_CERT,
390 p->cert_path) == -1)
391 return -1;
393 if (p->key_path != NULL &&
394 config_open_send(ps, IMSG_RECONF_PROXY_KEY,
395 p->key_path) == -1)
396 return -1;
398 if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1)
399 return -1;
402 if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1)
403 return -1;
406 return 0;
409 static int
410 load_file(int fd, uint8_t **data, size_t *len)
412 struct stat sb;
413 FILE *fp;
414 size_t r;
416 if (fstat(fd, &sb) == -1)
417 fatal("fstat");
419 if ((fp = fdopen(fd, "r")) == NULL)
420 fatal("fdopen");
422 if (sb.st_size < 0 /* || sb.st_size > SIZE_MAX */) {
423 log_warnx("file too large");
424 fclose(fp);
425 return -1;
427 *len = sb.st_size;
429 if ((*data = malloc(*len)) == NULL)
430 fatal("malloc");
432 r = fread(*data, 1, *len, fp);
433 if (r != *len) {
434 log_warn("read");
435 fclose(fp);
436 free(*data);
437 return -1;
440 fclose(fp);
441 return 0;
444 int
445 config_recv(struct conf *conf, struct imsg *imsg)
447 static struct vhost *h;
448 static struct proxy *p;
449 struct privsep *ps = conf->ps;
450 struct etm m;
451 struct fcgi *fcgi;
452 struct vhost *vh, vht;
453 struct location *loc;
454 struct envlist *env;
455 struct alist *alias;
456 struct proxy *proxy;
457 size_t datalen;
459 datalen = IMSG_DATA_SIZE(imsg);
461 switch (imsg->hdr.type) {
462 case IMSG_RECONF_START:
463 config_free();
464 h = NULL;
465 p = NULL;
466 break;
468 case IMSG_RECONF_MIME:
469 IMSG_SIZE_CHECK(imsg, &m);
470 memcpy(&m, imsg->data, datalen);
471 if (m.mime[sizeof(m.mime) - 1] != '\0' ||
472 m.ext[sizeof(m.ext) - 1] != '\0')
473 fatal("received corrupted IMSG_RECONF_MIME");
474 if (add_mime(&conf->mime, m.mime, m.ext) == -1)
475 fatal("failed to add mime mapping %s -> %s",
476 m.mime, m.ext);
477 break;
479 case IMSG_RECONF_PROTOS:
480 IMSG_SIZE_CHECK(imsg, &conf->protos);
481 memcpy(&conf->protos, imsg->data, datalen);
482 break;
484 case IMSG_RECONF_PORT:
485 IMSG_SIZE_CHECK(imsg, &conf->port);
486 memcpy(&conf->port, imsg->data, datalen);
487 break;
489 case IMSG_RECONF_SOCK4:
490 if (conf->sock4 != -1)
491 fatalx("socket ipv4 already recv'd");
492 if (imsg->fd == -1)
493 fatalx("missing socket for IMSG_RECONF_SOCK4");
494 conf->sock4 = imsg->fd;
495 event_set(&conf->evsock4, conf->sock4, EV_READ|EV_PERSIST,
496 do_accept, NULL);
497 break;
499 case IMSG_RECONF_SOCK6:
500 if (conf->sock6 != -1)
501 fatalx("socket ipv6 already recv'd");
502 if (imsg->fd == -1)
503 fatalx("missing socket for IMSG_RECONF_SOCK6");
504 conf->sock6 = imsg->fd;
505 event_set(&conf->evsock6, conf->sock6, EV_READ|EV_PERSIST,
506 do_accept, NULL);
507 break;
509 case IMSG_RECONF_FCGI:
510 IMSG_SIZE_CHECK(imsg, fcgi);
511 fcgi = xcalloc(1, sizeof(*fcgi));
512 memcpy(fcgi, imsg->data, datalen);
513 log_debug("received fcgi %s", fcgi->path);
514 TAILQ_INSERT_TAIL(&conf->fcgi, fcgi, fcgi);
515 break;
517 case IMSG_RECONF_HOST:
518 IMSG_SIZE_CHECK(imsg, &vht);
519 memcpy(&vht, imsg->data, datalen);
520 vh = new_vhost();
521 strlcpy(vh->domain, vht.domain, sizeof(vh->domain));
522 h = vh;
523 TAILQ_INSERT_TAIL(&hosts, h, vhosts);
525 /* reset proxy */
526 p = NULL;
527 break;
529 case IMSG_RECONF_CERT:
530 log_debug("receiving cert");
531 if (h == NULL)
532 fatalx("recv'd cert without host");
533 if (h->cert != NULL)
534 fatalx("cert already received");
535 if (imsg->fd == -1)
536 fatalx("no fd for IMSG_RECONF_CERT");
537 if (load_file(imsg->fd, &h->cert, &h->certlen) == -1)
538 fatalx("failed to load cert for %s",
539 h->domain);
540 break;
542 case IMSG_RECONF_KEY:
543 log_debug("receiving key");
544 if (h == NULL)
545 fatalx("recv'd key without host");
546 if (h->key != NULL)
547 fatalx("key already received");
548 if (imsg->fd == -1)
549 fatalx("no fd for IMSG_RECONF_KEY");
550 if (load_file(imsg->fd, &h->key, &h->keylen) == -1)
551 fatalx("failed to load key for %s",
552 h->domain);
553 break;
555 case IMSG_RECONF_OCSP:
556 log_debug("receiving ocsp");
557 if (h == NULL)
558 fatalx("recv'd ocsp without host");
559 if (h->ocsp != NULL)
560 fatalx("ocsp already received");
561 if (imsg->fd == -1)
562 fatalx("no fd for IMSG_RECONF_OCSP");
563 if (load_file(imsg->fd, &h->ocsp, &h->ocsplen) == -1)
564 fatalx("failed to load ocsp for %s",
565 h->domain);
566 break;
568 case IMSG_RECONF_LOC:
569 if (h == NULL)
570 fatalx("recv'd location without host");
571 IMSG_SIZE_CHECK(imsg, loc);
573 //loc = new_location();
574 loc = xcalloc(1, sizeof(*loc));
575 loc->dirfd = -1;
576 loc->fcgi = -1;
578 memcpy(loc, imsg->data, datalen);
580 if (imsg->fd != -1) {
581 loc->reqca = load_ca(imsg->fd);
582 if (loc->reqca == NULL)
583 fatalx("failed to load CA");
586 TAILQ_INSERT_TAIL(&h->locations, loc, locations);
587 break;
589 case IMSG_RECONF_ENV:
590 if (h == NULL)
591 fatalx("recv'd env without host");
592 IMSG_SIZE_CHECK(imsg, env);
593 env = xcalloc(1, sizeof(*env));
594 memcpy(env, imsg->data, datalen);
595 TAILQ_INSERT_TAIL(&h->params, env, envs);
596 break;
598 case IMSG_RECONF_ALIAS:
599 if (h == NULL)
600 fatalx("recv'd alias without host");
601 IMSG_SIZE_CHECK(imsg, alias);
602 alias = xcalloc(1, sizeof(*alias));
603 memcpy(alias, imsg->data, datalen);
604 TAILQ_INSERT_TAIL(&h->aliases, alias, aliases);
605 break;
607 case IMSG_RECONF_PROXY:
608 log_debug("receiving proxy");
609 if (h == NULL)
610 fatalx("recv'd proxy without host");
611 IMSG_SIZE_CHECK(imsg, proxy);
612 proxy = xcalloc(1, sizeof(*proxy));
613 memcpy(proxy, imsg->data, datalen);
615 if (imsg->fd != -1) {
616 proxy->reqca = load_ca(imsg->fd);
617 if (proxy->reqca == NULL)
618 fatal("failed to load CA");
621 TAILQ_INSERT_TAIL(&h->proxies, proxy, proxies);
622 p = proxy;
623 break;
625 case IMSG_RECONF_PROXY_CERT:
626 log_debug("receiving proxy cert");
627 if (p == NULL)
628 fatalx("recv'd proxy cert without proxy");
629 if (p->cert != NULL)
630 fatalx("proxy cert already received");
631 if (imsg->fd == -1)
632 fatalx("no fd for IMSG_RECONF_PROXY_CERT");
633 if (load_file(imsg->fd, &p->cert, &p->certlen) == -1)
634 fatalx("failed to load cert for proxy %s of %s",
635 p->host, h->domain);
636 break;
638 case IMSG_RECONF_PROXY_KEY:
639 log_debug("receiving proxy key");
640 if (p == NULL)
641 fatalx("recv'd proxy key without proxy");
642 if (p->key != NULL)
643 fatalx("proxy key already received");
644 if (imsg->fd == -1)
645 fatalx("no fd for IMSG_RECONF_PROXY_KEY");
646 if (load_file(imsg->fd, &p->key, &p->keylen) == -1)
647 fatalx("failed to load key for proxy %s of %s",
648 p->host, h->domain);
649 break;
651 case IMSG_RECONF_END:
652 if (proc_compose(ps, PROC_PARENT, IMSG_RECONF_DONE,
653 NULL, 0) == -1)
654 return -1;
655 break;
657 default:
658 return -1;
661 return 0;