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 conf.port = 1965;
36 conf.ipv6 = 0;
37 conf.protos = TLS_PROTOCOL_TLSv1_2 | TLS_PROTOCOL_TLSv1_3;
39 init_mime(&conf.mime);
41 conf.prefork = 3;
43 conf.sock4 = -1;
44 conf.sock6 = -1;
45 }
47 void
48 config_free(void)
49 {
50 struct privsep *ps;
51 struct vhost *h, *th;
52 struct location *l, *tl;
53 struct proxy *p, *tp;
54 struct envlist *e, *te;
55 struct alist *a, *ta;
57 ps = conf.ps;
59 if (conf.sock4 != -1) {
60 event_del(&conf.evsock4);
61 close(conf.sock4);
62 }
64 if (conf.sock6 != -1) {
65 event_del(&conf.evsock6);
66 close(conf.sock6);
67 }
69 free_mime(&conf.mime);
70 memset(&conf, 0, sizeof(conf));
72 conf.ps = ps;
73 conf.sock4 = conf.sock6 = -1;
74 conf.protos = TLS_PROTOCOL_TLSv1_2 | TLS_PROTOCOL_TLSv1_3;
75 init_mime(&conf.mime);
77 TAILQ_FOREACH_SAFE(h, &hosts, vhosts, th) {
78 free(h->cert_path);
79 free(h->key_path);
80 free(h->ocsp_path);
81 free(h->cert);
82 free(h->key);
83 free(h->ocsp);
85 TAILQ_FOREACH_SAFE(l, &h->locations, locations, tl) {
86 TAILQ_REMOVE(&h->locations, l, locations);
88 if (l->dirfd != -1)
89 close(l->dirfd);
91 free(l->reqca_path);
92 X509_STORE_free(l->reqca);
93 free(l);
94 }
96 TAILQ_FOREACH_SAFE(e, &h->params, envs, te) {
97 TAILQ_REMOVE(&h->params, e, envs);
98 free(e);
99 }
101 TAILQ_FOREACH_SAFE(a, &h->aliases, aliases, ta) {
102 TAILQ_REMOVE(&h->aliases, a, aliases);
103 free(a);
106 TAILQ_FOREACH_SAFE(p, &h->proxies, proxies, tp) {
107 TAILQ_REMOVE(&h->proxies, p, proxies);
108 free(p->cert_path);
109 free(p->cert);
110 free(p->key_path);
111 free(p->key);
112 free(p->reqca_path);
113 X509_STORE_free(p->reqca);
114 free(p);
117 TAILQ_REMOVE(&hosts, h, vhosts);
118 free(h);
121 memset(fcgi, 0, sizeof(fcgi));
124 static int
125 config_send_file(struct privsep *ps, int type, int fd, void *data, size_t l)
127 int n, m, id, d;
129 id = PROC_SERVER;
130 n = -1;
131 proc_range(ps, id, &n, &m);
132 for (n = 0; n < m; ++n) {
133 d = -1;
134 if (fd != -1 && (d = dup(fd)) == -1)
135 fatal("dup %d", fd);
136 if (proc_compose_imsg(ps, id, n, type, -1, d, data, l)
137 == -1)
138 return -1;
141 if (fd != -1)
142 close(fd);
143 return 0;
146 static int
147 config_open_send(struct privsep *ps, int type, const char *path)
149 int fd;
151 log_debug("sending %s", path);
153 if ((fd = open(path, O_RDONLY)) == -1)
154 fatal("can't open %s", path);
156 return config_send_file(ps, type, fd, NULL, 0);
159 static int
160 make_socket(int port, int family)
162 int sock, v;
163 struct sockaddr_in addr4;
164 struct sockaddr_in6 addr6;
165 struct sockaddr *addr;
166 socklen_t len;
168 switch (family) {
169 case AF_INET:
170 memset(&addr4, 0, sizeof(addr4));
171 addr4.sin_family = family;
172 addr4.sin_port = htons(port);
173 addr4.sin_addr.s_addr = INADDR_ANY;
174 addr = (struct sockaddr*)&addr4;
175 len = sizeof(addr4);
176 break;
178 case AF_INET6:
179 memset(&addr6, 0, sizeof(addr6));
180 addr6.sin6_family = AF_INET6;
181 addr6.sin6_port = htons(port);
182 addr6.sin6_addr = in6addr_any;
183 addr = (struct sockaddr*)&addr6;
184 len = sizeof(addr6);
185 break;
187 default:
188 /* unreachable */
189 abort();
192 if ((sock = socket(family, SOCK_STREAM, 0)) == -1)
193 fatal("socket");
195 v = 1;
196 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v)) == -1)
197 fatal("setsockopt(SO_REUSEADDR)");
199 v = 1;
200 if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &v, sizeof(v)) == -1)
201 fatal("setsockopt(SO_REUSEPORT)");
203 mark_nonblock(sock);
205 if (bind(sock, addr, len) == -1)
206 fatal("bind");
208 if (listen(sock, 16) == -1)
209 fatal("listen");
211 return sock;
214 static int
215 config_send_socks(struct conf *conf)
217 struct privsep *ps = conf->ps;
218 int sock;
220 if ((sock = make_socket(conf->port, AF_INET)) == -1)
221 return -1;
223 if (config_send_file(ps, IMSG_RECONF_SOCK4, sock, NULL, 0) == -1)
224 return -1;
226 if (!conf->ipv6)
227 return 0;
229 if ((sock = make_socket(conf->port, AF_INET6)) == -1)
230 return -1;
232 if (config_send_file(ps, IMSG_RECONF_SOCK6, sock, NULL, 0) == -1)
233 return -1;
235 return 0;
238 int
239 config_send(struct conf *conf, struct fcgi *fcgi, struct vhosthead *hosts)
241 struct privsep *ps = conf->ps;
242 struct etm *m;
243 struct vhost *h;
244 struct location *l;
245 struct proxy *p;
246 struct envlist *e;
247 struct alist *a;
248 size_t i;
249 int fd;
251 for (i = 0; i < conf->mime.len; ++i) {
252 m = &conf->mime.t[i];
253 if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_MIME,
254 m, sizeof(*m)) == -1)
255 return -1;
258 if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_PROTOS,
259 &conf->protos, sizeof(conf->protos)) == -1)
260 return -1;
262 if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_PORT,
263 &conf->port, sizeof(conf->port)) == -1)
264 return -1;
266 if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1)
267 return -1;
269 if (config_send_socks(conf) == -1)
270 return -1;
272 if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1)
273 return -1;
275 for (i = 0; i < FCGI_MAX; ++i) {
276 if (*fcgi[i].path == '\0')
277 break;
278 if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_FCGI,
279 &fcgi[i], sizeof(fcgi[i])) == -1)
280 return -1;
283 TAILQ_FOREACH(h, hosts, vhosts) {
284 struct vhost vcopy;
286 memcpy(&vcopy, h, sizeof(vcopy));
287 vcopy.cert_path = NULL;
288 vcopy.key_path = NULL;
289 vcopy.ocsp_path = NULL;
291 log_debug("sending host %s", h->domain);
293 if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_HOST,
294 &vcopy, sizeof(vcopy)) == -1)
295 return -1;
297 log_debug("sending certificate %s", h->cert_path);
298 if ((fd = open(h->cert_path, O_RDONLY)) == -1)
299 fatal("can't open %s", h->cert_path);
300 if (config_send_file(ps, IMSG_RECONF_CERT, fd, NULL, 0) == -1)
301 return -1;
303 log_debug("sending key %s", h->key_path);
304 if ((fd = open(h->key_path, O_RDONLY)) == -1)
305 fatal("can't open %s", h->key_path);
306 if (config_send_file(ps, IMSG_RECONF_KEY, fd, NULL, 0) == -1)
307 return -1;
309 if (h->ocsp_path != NULL) {
310 log_debug("sending ocsp %s", h->ocsp_path);
311 if ((fd = open(h->ocsp_path, O_RDONLY)) == -1)
312 fatal("can't open %s", h->ocsp_path);
313 if (config_send_file(ps, IMSG_RECONF_OCSP, fd,
314 NULL, 0) == -1)
315 return -1;
318 TAILQ_FOREACH(l, &h->locations, locations) {
319 struct location lcopy;
320 int fd = -1;
322 memcpy(&lcopy, l, sizeof(lcopy));
323 lcopy.reqca_path = NULL;
324 lcopy.reqca = NULL;
325 lcopy.dirfd = -1;
326 memset(&lcopy.locations, 0, sizeof(lcopy.locations));
328 if (l->reqca_path != NULL &&
329 (fd = open(l->reqca_path, O_RDONLY)) == -1)
330 fatal("can't open %s", l->reqca_path);
332 if (config_send_file(ps, IMSG_RECONF_LOC, fd,
333 &lcopy, sizeof(lcopy)) == -1)
334 return -1;
337 if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1)
338 return -1;
340 TAILQ_FOREACH(e, &h->params, envs) {
341 if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_ENV,
342 e, sizeof(*e)) == -1)
343 return -1;
346 if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1)
347 return -1;
349 TAILQ_FOREACH(a, &h->aliases, aliases) {
350 if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_ALIAS,
351 a, sizeof(*a)) == -1)
352 return -1;
355 if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1)
356 return -1;
358 TAILQ_FOREACH(p, &h->proxies, proxies) {
359 struct proxy pcopy;
360 int fd = -1;
362 memcpy(&pcopy, p, sizeof(pcopy));
363 pcopy.cert_path = NULL;
364 pcopy.cert = NULL;
365 pcopy.certlen = 0;
366 pcopy.key_path = NULL;
367 pcopy.key = NULL;
368 pcopy.keylen = 0;
369 pcopy.reqca_path = NULL;
370 pcopy.reqca = NULL;
372 if (p->reqca_path != NULL) {
373 fd = open(p->reqca_path, O_RDONLY);
374 if (fd == -1)
375 fatal("can't open %s", p->reqca_path);
378 if (config_send_file(ps, IMSG_RECONF_PROXY, fd,
379 &pcopy, sizeof(pcopy)) == -1)
380 return -1;
382 if (p->cert_path != NULL &&
383 config_open_send(ps, IMSG_RECONF_PROXY_CERT,
384 p->cert_path) == -1)
385 return -1;
387 if (p->key_path != NULL &&
388 config_open_send(ps, IMSG_RECONF_PROXY_KEY,
389 p->key_path) == -1)
390 return -1;
392 if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1)
393 return -1;
396 if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1)
397 return -1;
400 return 0;
403 static int
404 load_file(int fd, uint8_t **data, size_t *len)
406 struct stat sb;
407 FILE *fp;
408 size_t r;
410 if (fstat(fd, &sb) == -1)
411 fatal("fstat");
413 if ((fp = fdopen(fd, "r")) == NULL)
414 fatal("fdopen");
416 if (sb.st_size < 0 /* || sb.st_size > SIZE_MAX */) {
417 log_warnx("file too large");
418 fclose(fp);
419 return -1;
421 *len = sb.st_size;
423 if ((*data = malloc(*len)) == NULL)
424 fatal("malloc");
426 r = fread(*data, 1, *len, fp);
427 if (r != *len) {
428 log_warn("read");
429 fclose(fp);
430 free(*data);
431 return -1;
434 fclose(fp);
435 return 0;
438 int
439 config_recv(struct conf *conf, struct imsg *imsg)
441 static struct vhost *h;
442 static struct proxy *p;
443 struct privsep *ps = conf->ps;
444 struct etm m;
445 struct fcgi *f;
446 struct vhost *vh, vht;
447 struct location *loc;
448 struct envlist *env;
449 struct alist *alias;
450 struct proxy *proxy;
451 size_t i, datalen;
453 datalen = IMSG_DATA_SIZE(imsg);
455 switch (imsg->hdr.type) {
456 case IMSG_RECONF_START:
457 config_free();
458 h = NULL;
459 p = NULL;
460 break;
462 case IMSG_RECONF_MIME:
463 IMSG_SIZE_CHECK(imsg, &m);
464 memcpy(&m, imsg->data, datalen);
465 if (m.mime[sizeof(m.mime) - 1] != '\0' ||
466 m.ext[sizeof(m.ext) - 1] != '\0')
467 fatal("received corrupted IMSG_RECONF_MIME");
468 if (add_mime(&conf->mime, m.mime, m.ext) == -1)
469 fatal("failed to add mime mapping %s -> %s",
470 m.mime, m.ext);
471 break;
473 case IMSG_RECONF_PROTOS:
474 IMSG_SIZE_CHECK(imsg, &conf->protos);
475 memcpy(&conf->protos, imsg->data, datalen);
476 break;
478 case IMSG_RECONF_PORT:
479 IMSG_SIZE_CHECK(imsg, &conf->port);
480 memcpy(&conf->port, imsg->data, datalen);
481 break;
483 case IMSG_RECONF_SOCK4:
484 if (conf->sock4 != -1)
485 fatalx("socket ipv4 already recv'd");
486 if (imsg->fd == -1)
487 fatalx("missing socket for IMSG_RECONF_SOCK4");
488 conf->sock4 = imsg->fd;
489 event_set(&conf->evsock4, conf->sock4, EV_READ|EV_PERSIST,
490 do_accept, NULL);
491 break;
493 case IMSG_RECONF_SOCK6:
494 if (conf->sock6 != -1)
495 fatalx("socket ipv6 already recv'd");
496 if (imsg->fd == -1)
497 fatalx("missing socket for IMSG_RECONF_SOCK6");
498 conf->sock6 = imsg->fd;
499 event_set(&conf->evsock6, conf->sock6, EV_READ|EV_PERSIST,
500 do_accept, NULL);
501 break;
503 case IMSG_RECONF_FCGI:
504 for (i = 0; i < FCGI_MAX; ++i) {
505 f = &fcgi[i];
506 if (*f->path != '\0')
507 continue;
508 IMSG_SIZE_CHECK(imsg, f);
509 memcpy(f, imsg->data, datalen);
510 break;
512 if (i == FCGI_MAX)
513 fatalx("recv too many fcgi");
514 break;
516 case IMSG_RECONF_HOST:
517 IMSG_SIZE_CHECK(imsg, &vht);
518 memcpy(&vht, imsg->data, datalen);
519 vh = new_vhost();
520 strlcpy(vh->domain, vht.domain, sizeof(vh->domain));
521 h = vh;
522 TAILQ_INSERT_TAIL(&hosts, h, vhosts);
524 /* reset proxy */
525 p = NULL;
526 break;
528 case IMSG_RECONF_CERT:
529 log_debug("receiving cert");
530 if (h == NULL)
531 fatalx("recv'd cert without host");
532 if (h->cert != NULL)
533 fatalx("cert already received");
534 if (imsg->fd == -1)
535 fatalx("no fd for IMSG_RECONF_CERT");
536 if (load_file(imsg->fd, &h->cert, &h->certlen) == -1)
537 fatalx("failed to load cert for %s",
538 h->domain);
539 break;
541 case IMSG_RECONF_KEY:
542 log_debug("receiving key");
543 if (h == NULL)
544 fatalx("recv'd key without host");
545 if (h->key != NULL)
546 fatalx("key already received");
547 if (imsg->fd == -1)
548 fatalx("no fd for IMSG_RECONF_KEY");
549 if (load_file(imsg->fd, &h->key, &h->keylen) == -1)
550 fatalx("failed to load key for %s",
551 h->domain);
552 break;
554 case IMSG_RECONF_OCSP:
555 log_debug("receiving ocsp");
556 if (h == NULL)
557 fatalx("recv'd ocsp without host");
558 if (h->ocsp != NULL)
559 fatalx("ocsp already received");
560 if (imsg->fd == -1)
561 fatalx("no fd for IMSG_RECONF_OCSP");
562 if (load_file(imsg->fd, &h->ocsp, &h->ocsplen) == -1)
563 fatalx("failed to load ocsp for %s",
564 h->domain);
565 break;
567 case IMSG_RECONF_LOC:
568 if (h == NULL)
569 fatalx("recv'd location without host");
570 IMSG_SIZE_CHECK(imsg, loc);
572 //loc = new_location();
573 loc = xcalloc(1, sizeof(*loc));
574 loc->dirfd = -1;
575 loc->fcgi = -1;
577 memcpy(loc, imsg->data, datalen);
579 if (imsg->fd != -1) {
580 loc->reqca = load_ca(imsg->fd);
581 if (loc->reqca == NULL)
582 fatalx("failed to load CA");
585 TAILQ_INSERT_TAIL(&h->locations, loc, locations);
586 break;
588 case IMSG_RECONF_ENV:
589 if (h == NULL)
590 fatalx("recv'd env without host");
591 IMSG_SIZE_CHECK(imsg, env);
592 env = xcalloc(1, sizeof(*env));
593 memcpy(env, imsg->data, datalen);
594 TAILQ_INSERT_TAIL(&h->params, env, envs);
595 break;
597 case IMSG_RECONF_ALIAS:
598 if (h == NULL)
599 fatalx("recv'd alias without host");
600 IMSG_SIZE_CHECK(imsg, alias);
601 alias = xcalloc(1, sizeof(*alias));
602 memcpy(alias, imsg->data, datalen);
603 TAILQ_INSERT_TAIL(&h->aliases, alias, aliases);
604 break;
606 case IMSG_RECONF_PROXY:
607 log_debug("receiving proxy");
608 if (h == NULL)
609 fatalx("recv'd proxy without host");
610 IMSG_SIZE_CHECK(imsg, proxy);
611 proxy = xcalloc(1, sizeof(*proxy));
612 memcpy(proxy, imsg->data, datalen);
614 if (imsg->fd != -1) {
615 proxy->reqca = load_ca(imsg->fd);
616 if (proxy->reqca == NULL)
617 fatal("failed to load CA");
620 TAILQ_INSERT_TAIL(&h->proxies, proxy, proxies);
621 p = proxy;
622 break;
624 case IMSG_RECONF_PROXY_CERT:
625 log_debug("receiving proxy cert");
626 if (p == NULL)
627 fatalx("recv'd proxy cert without proxy");
628 if (p->cert != NULL)
629 fatalx("proxy cert already received");
630 if (imsg->fd == -1)
631 fatalx("no fd for IMSG_RECONF_PROXY_CERT");
632 if (load_file(imsg->fd, &p->cert, &p->certlen) == -1)
633 fatalx("failed to load cert for proxy %s of %s",
634 p->host, h->domain);
635 break;
637 case IMSG_RECONF_PROXY_KEY:
638 log_debug("receiving proxy key");
639 if (p == NULL)
640 fatalx("recv'd proxy key without proxy");
641 if (p->key != NULL)
642 fatalx("proxy key already received");
643 if (imsg->fd == -1)
644 fatalx("no fd for IMSG_RECONF_PROXY_KEY");
645 if (load_file(imsg->fd, &p->key, &p->keylen) == -1)
646 fatalx("failed to load key for proxy %s of %s",
647 p->host, h->domain);
648 break;
650 case IMSG_RECONF_END:
651 if (proc_compose(ps, PROC_PARENT, IMSG_RECONF_DONE,
652 NULL, 0) == -1)
653 return -1;
654 break;
656 default:
657 return -1;
660 return 0;