1*f1b790a5Sclaudio /* $OpenBSD: control.c,v 1.14 2024/11/21 13:38:15 claudio Exp $ */ 253293e44Sflorian 353293e44Sflorian /* 453293e44Sflorian * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 553293e44Sflorian * 653293e44Sflorian * Permission to use, copy, modify, and distribute this software for any 753293e44Sflorian * purpose with or without fee is hereby granted, provided that the above 853293e44Sflorian * copyright notice and this permission notice appear in all copies. 953293e44Sflorian * 1053293e44Sflorian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1153293e44Sflorian * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1253293e44Sflorian * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1353293e44Sflorian * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1453293e44Sflorian * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1553293e44Sflorian * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1653293e44Sflorian * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1753293e44Sflorian */ 1853293e44Sflorian #include <sys/types.h> 1953293e44Sflorian #include <sys/queue.h> 2053293e44Sflorian #include <sys/stat.h> 2153293e44Sflorian #include <sys/socket.h> 2253293e44Sflorian #include <sys/uio.h> 2353293e44Sflorian #include <sys/un.h> 2453293e44Sflorian 2553293e44Sflorian #include <netinet/in.h> 2653293e44Sflorian #include <net/if.h> 2753293e44Sflorian 2853293e44Sflorian #include <errno.h> 2953293e44Sflorian #include <event.h> 3053293e44Sflorian #include <imsg.h> 3153293e44Sflorian #include <stdlib.h> 3253293e44Sflorian #include <string.h> 3353293e44Sflorian #include <unistd.h> 3453293e44Sflorian 3553293e44Sflorian #include "log.h" 3653293e44Sflorian #include "rad.h" 3753293e44Sflorian #include "control.h" 3853293e44Sflorian #include "frontend.h" 3953293e44Sflorian 4053293e44Sflorian #define CONTROL_BACKLOG 5 4153293e44Sflorian 42d258785eSflorian struct { 43d258785eSflorian struct event ev; 44d258785eSflorian struct event evt; 45d258785eSflorian int fd; 46d258785eSflorian } control_state = {.fd = -1}; 47d258785eSflorian 48d258785eSflorian struct ctl_conn { 49d258785eSflorian TAILQ_ENTRY(ctl_conn) entry; 50d258785eSflorian struct imsgev iev; 51d258785eSflorian }; 52d258785eSflorian 53d258785eSflorian TAILQ_HEAD(ctl_conns, ctl_conn) ctl_conns = TAILQ_HEAD_INITIALIZER(ctl_conns); 54d258785eSflorian 5553293e44Sflorian struct ctl_conn *control_connbyfd(int); 5653293e44Sflorian struct ctl_conn *control_connbypid(pid_t); 5753293e44Sflorian void control_close(int); 5853293e44Sflorian 5953293e44Sflorian int 6053293e44Sflorian control_init(char *path) 6153293e44Sflorian { 6253293e44Sflorian struct sockaddr_un sun; 6353293e44Sflorian int fd; 6453293e44Sflorian mode_t old_umask; 6553293e44Sflorian 6653293e44Sflorian if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 6753293e44Sflorian 0)) == -1) { 6853293e44Sflorian log_warn("%s: socket", __func__); 6953293e44Sflorian return (-1); 7053293e44Sflorian } 7153293e44Sflorian 7253293e44Sflorian memset(&sun, 0, sizeof(sun)); 7353293e44Sflorian sun.sun_family = AF_UNIX; 7453293e44Sflorian strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); 7553293e44Sflorian 7653293e44Sflorian if (unlink(path) == -1) 7753293e44Sflorian if (errno != ENOENT) { 7853293e44Sflorian log_warn("%s: unlink %s", __func__, path); 7953293e44Sflorian close(fd); 8053293e44Sflorian return (-1); 8153293e44Sflorian } 8253293e44Sflorian 8353293e44Sflorian old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); 8453293e44Sflorian if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { 8553293e44Sflorian log_warn("%s: bind: %s", __func__, path); 8653293e44Sflorian close(fd); 8753293e44Sflorian umask(old_umask); 8853293e44Sflorian return (-1); 8953293e44Sflorian } 9053293e44Sflorian umask(old_umask); 9153293e44Sflorian 9253293e44Sflorian if (chmod(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) { 9353293e44Sflorian log_warn("%s: chmod", __func__); 9453293e44Sflorian close(fd); 9553293e44Sflorian (void)unlink(path); 9653293e44Sflorian return (-1); 9753293e44Sflorian } 9853293e44Sflorian 99a778af8bSflorian return (fd); 10053293e44Sflorian } 10153293e44Sflorian 10253293e44Sflorian int 103d258785eSflorian control_listen(int fd) 10453293e44Sflorian { 105d258785eSflorian if (control_state.fd != -1) 106d258785eSflorian fatalx("%s: received unexpected controlsock", __func__); 107d258785eSflorian 1083e9f42c2Sderaadt control_state.fd = fd; 10953293e44Sflorian if (listen(control_state.fd, CONTROL_BACKLOG) == -1) { 11053293e44Sflorian log_warn("%s: listen", __func__); 11153293e44Sflorian return (-1); 11253293e44Sflorian } 11353293e44Sflorian 11453293e44Sflorian event_set(&control_state.ev, control_state.fd, EV_READ, 11553293e44Sflorian control_accept, NULL); 11653293e44Sflorian event_add(&control_state.ev, NULL); 11753293e44Sflorian evtimer_set(&control_state.evt, control_accept, NULL); 11853293e44Sflorian 11953293e44Sflorian return (0); 12053293e44Sflorian } 12153293e44Sflorian 12253293e44Sflorian void 12353293e44Sflorian control_accept(int listenfd, short event, void *bula) 12453293e44Sflorian { 12553293e44Sflorian int connfd; 12653293e44Sflorian socklen_t len; 12753293e44Sflorian struct sockaddr_un sun; 12853293e44Sflorian struct ctl_conn *c; 12953293e44Sflorian 13053293e44Sflorian event_add(&control_state.ev, NULL); 13153293e44Sflorian if ((event & EV_TIMEOUT)) 13253293e44Sflorian return; 13353293e44Sflorian 13453293e44Sflorian len = sizeof(sun); 13553293e44Sflorian if ((connfd = accept4(listenfd, (struct sockaddr *)&sun, &len, 13653293e44Sflorian SOCK_CLOEXEC | SOCK_NONBLOCK)) == -1) { 13753293e44Sflorian /* 13853293e44Sflorian * Pause accept if we are out of file descriptors, or 13953293e44Sflorian * libevent will haunt us here too. 14053293e44Sflorian */ 14153293e44Sflorian if (errno == ENFILE || errno == EMFILE) { 14253293e44Sflorian struct timeval evtpause = { 1, 0 }; 14353293e44Sflorian 14453293e44Sflorian event_del(&control_state.ev); 14553293e44Sflorian evtimer_add(&control_state.evt, &evtpause); 14653293e44Sflorian } else if (errno != EWOULDBLOCK && errno != EINTR && 14753293e44Sflorian errno != ECONNABORTED) 14853293e44Sflorian log_warn("%s: accept4", __func__); 14953293e44Sflorian return; 15053293e44Sflorian } 15153293e44Sflorian 15253293e44Sflorian if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) { 15353293e44Sflorian log_warn("%s: calloc", __func__); 15453293e44Sflorian close(connfd); 15553293e44Sflorian return; 15653293e44Sflorian } 15753293e44Sflorian 158*f1b790a5Sclaudio if (imsgbuf_init(&c->iev.ibuf, connfd) == -1) { 159*f1b790a5Sclaudio log_warn("%s: imsgbuf_init", __func__); 160*f1b790a5Sclaudio close(connfd); 161*f1b790a5Sclaudio free(c); 162*f1b790a5Sclaudio return; 163*f1b790a5Sclaudio } 16453293e44Sflorian c->iev.handler = control_dispatch_imsg; 16553293e44Sflorian c->iev.events = EV_READ; 16653293e44Sflorian event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events, 16753293e44Sflorian c->iev.handler, &c->iev); 16853293e44Sflorian event_add(&c->iev.ev, NULL); 16953293e44Sflorian 17053293e44Sflorian TAILQ_INSERT_TAIL(&ctl_conns, c, entry); 17153293e44Sflorian } 17253293e44Sflorian 17353293e44Sflorian struct ctl_conn * 17453293e44Sflorian control_connbyfd(int fd) 17553293e44Sflorian { 17653293e44Sflorian struct ctl_conn *c; 17753293e44Sflorian 17853293e44Sflorian TAILQ_FOREACH(c, &ctl_conns, entry) { 17953293e44Sflorian if (c->iev.ibuf.fd == fd) 18053293e44Sflorian break; 18153293e44Sflorian } 18253293e44Sflorian 18353293e44Sflorian return (c); 18453293e44Sflorian } 18553293e44Sflorian 18653293e44Sflorian struct ctl_conn * 18753293e44Sflorian control_connbypid(pid_t pid) 18853293e44Sflorian { 18953293e44Sflorian struct ctl_conn *c; 19053293e44Sflorian 19153293e44Sflorian TAILQ_FOREACH(c, &ctl_conns, entry) { 19253293e44Sflorian if (c->iev.ibuf.pid == pid) 19353293e44Sflorian break; 19453293e44Sflorian } 19553293e44Sflorian 19653293e44Sflorian return (c); 19753293e44Sflorian } 19853293e44Sflorian 19953293e44Sflorian void 20053293e44Sflorian control_close(int fd) 20153293e44Sflorian { 20253293e44Sflorian struct ctl_conn *c; 20353293e44Sflorian 20453293e44Sflorian if ((c = control_connbyfd(fd)) == NULL) { 20553293e44Sflorian log_warnx("%s: fd %d: not found", __func__, fd); 20653293e44Sflorian return; 20753293e44Sflorian } 20853293e44Sflorian 2099cbf9e90Sclaudio imsgbuf_clear(&c->iev.ibuf); 21053293e44Sflorian TAILQ_REMOVE(&ctl_conns, c, entry); 21153293e44Sflorian 21253293e44Sflorian event_del(&c->iev.ev); 21353293e44Sflorian close(c->iev.ibuf.fd); 21453293e44Sflorian 21553293e44Sflorian /* Some file descriptors are available again. */ 21653293e44Sflorian if (evtimer_pending(&control_state.evt, NULL)) { 21753293e44Sflorian evtimer_del(&control_state.evt); 21853293e44Sflorian event_add(&control_state.ev, NULL); 21953293e44Sflorian } 22053293e44Sflorian 22153293e44Sflorian free(c); 22253293e44Sflorian } 22353293e44Sflorian 22453293e44Sflorian void 22553293e44Sflorian control_dispatch_imsg(int fd, short event, void *bula) 22653293e44Sflorian { 22753293e44Sflorian struct ctl_conn *c; 22853293e44Sflorian struct imsg imsg; 22953293e44Sflorian ssize_t n; 23053293e44Sflorian int verbose; 23153293e44Sflorian 23253293e44Sflorian if ((c = control_connbyfd(fd)) == NULL) { 23353293e44Sflorian log_warnx("%s: fd %d: not found", __func__, fd); 23453293e44Sflorian return; 23553293e44Sflorian } 23653293e44Sflorian 23753293e44Sflorian if (event & EV_READ) { 238668e5ba9Sclaudio if (imsgbuf_read(&c->iev.ibuf) != 1) { 23953293e44Sflorian control_close(fd); 24053293e44Sflorian return; 24153293e44Sflorian } 24253293e44Sflorian } 24353293e44Sflorian if (event & EV_WRITE) { 244dd7efffeSclaudio if (imsgbuf_write(&c->iev.ibuf) == -1) { 24553293e44Sflorian control_close(fd); 24653293e44Sflorian return; 24753293e44Sflorian } 24853293e44Sflorian } 24953293e44Sflorian 25053293e44Sflorian for (;;) { 25153293e44Sflorian if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) { 25253293e44Sflorian control_close(fd); 25353293e44Sflorian return; 25453293e44Sflorian } 25553293e44Sflorian if (n == 0) 25653293e44Sflorian break; 25753293e44Sflorian 25853293e44Sflorian switch (imsg.hdr.type) { 25953293e44Sflorian case IMSG_CTL_RELOAD: 26053293e44Sflorian frontend_imsg_compose_main(imsg.hdr.type, 0, NULL, 0); 26153293e44Sflorian break; 26253293e44Sflorian case IMSG_CTL_LOG_VERBOSE: 263b17c900dSpamela if (IMSG_DATA_SIZE(imsg) != sizeof(verbose)) 26453293e44Sflorian break; 26553293e44Sflorian 26653293e44Sflorian /* Forward to all other processes. */ 26753293e44Sflorian frontend_imsg_compose_main(imsg.hdr.type, imsg.hdr.pid, 268b17c900dSpamela imsg.data, IMSG_DATA_SIZE(imsg)); 26953293e44Sflorian frontend_imsg_compose_engine(imsg.hdr.type, 270b17c900dSpamela imsg.hdr.pid, imsg.data, IMSG_DATA_SIZE(imsg)); 27153293e44Sflorian 27253293e44Sflorian memcpy(&verbose, imsg.data, sizeof(verbose)); 27353293e44Sflorian log_setverbose(verbose); 27453293e44Sflorian break; 27553293e44Sflorian default: 27653293e44Sflorian log_debug("%s: error handling imsg %d", __func__, 27753293e44Sflorian imsg.hdr.type); 27853293e44Sflorian break; 27953293e44Sflorian } 28053293e44Sflorian imsg_free(&imsg); 28153293e44Sflorian } 28253293e44Sflorian 28353293e44Sflorian imsg_event_add(&c->iev); 28453293e44Sflorian } 28553293e44Sflorian 28653293e44Sflorian int 28753293e44Sflorian control_imsg_relay(struct imsg *imsg) 28853293e44Sflorian { 28953293e44Sflorian struct ctl_conn *c; 29053293e44Sflorian 29153293e44Sflorian if ((c = control_connbypid(imsg->hdr.pid)) == NULL) 29253293e44Sflorian return (0); 29353293e44Sflorian 29453293e44Sflorian return (imsg_compose_event(&c->iev, imsg->hdr.type, 0, imsg->hdr.pid, 295b17c900dSpamela -1, imsg->data, IMSG_DATA_SIZE(*imsg))); 29653293e44Sflorian } 297