1*0e59d0d1Sclaudio /* $OpenBSD: control.c,v 1.9 2024/11/21 13:35:20 claudio Exp $ */ 2ad7c548dSflorian 3ad7c548dSflorian /* 4ad7c548dSflorian * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 5ad7c548dSflorian * 6ad7c548dSflorian * Permission to use, copy, modify, and distribute this software for any 7ad7c548dSflorian * purpose with or without fee is hereby granted, provided that the above 8ad7c548dSflorian * copyright notice and this permission notice appear in all copies. 9ad7c548dSflorian * 10ad7c548dSflorian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11ad7c548dSflorian * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12ad7c548dSflorian * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13ad7c548dSflorian * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14ad7c548dSflorian * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15ad7c548dSflorian * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16ad7c548dSflorian * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17ad7c548dSflorian */ 18ad7c548dSflorian #include <sys/types.h> 19ad7c548dSflorian #include <sys/queue.h> 20ad7c548dSflorian #include <sys/stat.h> 21ad7c548dSflorian #include <sys/socket.h> 22ad7c548dSflorian #include <sys/uio.h> 23ad7c548dSflorian #include <sys/un.h> 24ad7c548dSflorian 25ad7c548dSflorian #include <net/if.h> 26ad7c548dSflorian #include <netinet/in.h> 27ad7c548dSflorian 28ad7c548dSflorian #include <errno.h> 29ad7c548dSflorian #include <event.h> 30ad7c548dSflorian #include <imsg.h> 31763cddbdSflorian #include <stdio.h> 32ad7c548dSflorian #include <stdlib.h> 33ad7c548dSflorian #include <string.h> 34ad7c548dSflorian #include <unistd.h> 35ad7c548dSflorian 36ad7c548dSflorian #include "log.h" 37ad7c548dSflorian #include "dhcp6leased.h" 38ad7c548dSflorian #include "control.h" 39ad7c548dSflorian #include "frontend.h" 40ad7c548dSflorian 41ad7c548dSflorian #define CONTROL_BACKLOG 5 42ad7c548dSflorian 43ad7c548dSflorian struct { 44ad7c548dSflorian struct event ev; 45ad7c548dSflorian struct event evt; 46ad7c548dSflorian int fd; 47ad7c548dSflorian } control_state = {.fd = -1}; 48ad7c548dSflorian 49ad7c548dSflorian struct ctl_conn { 50ad7c548dSflorian TAILQ_ENTRY(ctl_conn) entry; 51ad7c548dSflorian struct imsgev iev; 52ad7c548dSflorian }; 53ad7c548dSflorian 54ad7c548dSflorian struct ctl_conn *control_connbyfd(int); 55ad7c548dSflorian struct ctl_conn *control_connbypid(pid_t); 56ad7c548dSflorian void control_close(int); 57ad7c548dSflorian 58ad7c548dSflorian TAILQ_HEAD(ctl_conns, ctl_conn) ctl_conns = TAILQ_HEAD_INITIALIZER(ctl_conns); 59ad7c548dSflorian 60ad7c548dSflorian int 61ad7c548dSflorian control_init(char *path) 62ad7c548dSflorian { 63ad7c548dSflorian struct sockaddr_un sun; 64ad7c548dSflorian int fd; 65ad7c548dSflorian mode_t old_umask; 66ad7c548dSflorian 67ad7c548dSflorian if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 68ad7c548dSflorian 0)) == -1) { 69ad7c548dSflorian log_warn("%s: socket", __func__); 70ad7c548dSflorian return (-1); 71ad7c548dSflorian } 72ad7c548dSflorian 73ad7c548dSflorian memset(&sun, 0, sizeof(sun)); 74ad7c548dSflorian sun.sun_family = AF_UNIX; 75ad7c548dSflorian strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); 76ad7c548dSflorian 77ad7c548dSflorian if (unlink(path) == -1) 78ad7c548dSflorian if (errno != ENOENT) { 79ad7c548dSflorian log_warn("%s: unlink %s", __func__, path); 80ad7c548dSflorian close(fd); 81ad7c548dSflorian return (-1); 82ad7c548dSflorian } 83ad7c548dSflorian 84ad7c548dSflorian old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); 85ad7c548dSflorian if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { 86ad7c548dSflorian log_warn("%s: bind: %s", __func__, path); 87ad7c548dSflorian close(fd); 88ad7c548dSflorian umask(old_umask); 89ad7c548dSflorian return (-1); 90ad7c548dSflorian } 91ad7c548dSflorian umask(old_umask); 92ad7c548dSflorian 93ad7c548dSflorian if (chmod(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) { 94ad7c548dSflorian log_warn("%s: chmod", __func__); 95ad7c548dSflorian close(fd); 96ad7c548dSflorian (void)unlink(path); 97ad7c548dSflorian return (-1); 98ad7c548dSflorian } 99ad7c548dSflorian 100ad7c548dSflorian return (fd); 101ad7c548dSflorian } 102ad7c548dSflorian 103ad7c548dSflorian int 104ad7c548dSflorian control_listen(int fd) 105ad7c548dSflorian { 106ad7c548dSflorian if (control_state.fd != -1) 107ad7c548dSflorian fatalx("%s: received unexpected controlsock", __func__); 108ad7c548dSflorian 109ad7c548dSflorian control_state.fd = fd; 110ad7c548dSflorian if (listen(control_state.fd, CONTROL_BACKLOG) == -1) { 111ad7c548dSflorian log_warn("%s: listen", __func__); 112ad7c548dSflorian return (-1); 113ad7c548dSflorian } 114ad7c548dSflorian 115ad7c548dSflorian event_set(&control_state.ev, control_state.fd, EV_READ, 116ad7c548dSflorian control_accept, NULL); 117ad7c548dSflorian event_add(&control_state.ev, NULL); 118ad7c548dSflorian evtimer_set(&control_state.evt, control_accept, NULL); 119ad7c548dSflorian 120ad7c548dSflorian return (0); 121ad7c548dSflorian } 122ad7c548dSflorian 123ad7c548dSflorian void 124ad7c548dSflorian control_accept(int listenfd, short event, void *bula) 125ad7c548dSflorian { 126ad7c548dSflorian int connfd; 127ad7c548dSflorian socklen_t len; 128ad7c548dSflorian struct sockaddr_un sun; 129ad7c548dSflorian struct ctl_conn *c; 130ad7c548dSflorian 131ad7c548dSflorian event_add(&control_state.ev, NULL); 132ad7c548dSflorian if ((event & EV_TIMEOUT)) 133ad7c548dSflorian return; 134ad7c548dSflorian 135ad7c548dSflorian len = sizeof(sun); 136ad7c548dSflorian if ((connfd = accept4(listenfd, (struct sockaddr *)&sun, &len, 137ad7c548dSflorian SOCK_CLOEXEC | SOCK_NONBLOCK)) == -1) { 138ad7c548dSflorian /* 139ad7c548dSflorian * Pause accept if we are out of file descriptors, or 140ad7c548dSflorian * libevent will haunt us here too. 141ad7c548dSflorian */ 142ad7c548dSflorian if (errno == ENFILE || errno == EMFILE) { 143ad7c548dSflorian struct timeval evtpause = { 1, 0 }; 144ad7c548dSflorian 145ad7c548dSflorian event_del(&control_state.ev); 146ad7c548dSflorian evtimer_add(&control_state.evt, &evtpause); 147ad7c548dSflorian } else if (errno != EWOULDBLOCK && errno != EINTR && 148ad7c548dSflorian errno != ECONNABORTED) 149ad7c548dSflorian log_warn("%s: accept4", __func__); 150ad7c548dSflorian return; 151ad7c548dSflorian } 152ad7c548dSflorian 153ad7c548dSflorian if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) { 154ad7c548dSflorian log_warn("%s: calloc", __func__); 155ad7c548dSflorian close(connfd); 156ad7c548dSflorian return; 157ad7c548dSflorian } 158ad7c548dSflorian 159*0e59d0d1Sclaudio if (imsgbuf_init(&c->iev.ibuf, connfd) == -1) { 160*0e59d0d1Sclaudio log_warn("%s: imsgbuf_init", __func__); 161*0e59d0d1Sclaudio close(connfd); 162*0e59d0d1Sclaudio free(c); 163*0e59d0d1Sclaudio return; 164*0e59d0d1Sclaudio } 165ad7c548dSflorian c->iev.handler = control_dispatch_imsg; 166ad7c548dSflorian c->iev.events = EV_READ; 167ad7c548dSflorian event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events, 168ad7c548dSflorian c->iev.handler, &c->iev); 169ad7c548dSflorian event_add(&c->iev.ev, NULL); 170ad7c548dSflorian 171ad7c548dSflorian TAILQ_INSERT_TAIL(&ctl_conns, c, entry); 172ad7c548dSflorian } 173ad7c548dSflorian 174ad7c548dSflorian struct ctl_conn * 175ad7c548dSflorian control_connbyfd(int fd) 176ad7c548dSflorian { 177ad7c548dSflorian struct ctl_conn *c; 178ad7c548dSflorian 179ad7c548dSflorian TAILQ_FOREACH(c, &ctl_conns, entry) { 180ad7c548dSflorian if (c->iev.ibuf.fd == fd) 181ad7c548dSflorian break; 182ad7c548dSflorian } 183ad7c548dSflorian 184ad7c548dSflorian return (c); 185ad7c548dSflorian } 186ad7c548dSflorian 187ad7c548dSflorian struct ctl_conn * 188ad7c548dSflorian control_connbypid(pid_t pid) 189ad7c548dSflorian { 190ad7c548dSflorian struct ctl_conn *c; 191ad7c548dSflorian 192ad7c548dSflorian TAILQ_FOREACH(c, &ctl_conns, entry) { 193ad7c548dSflorian if (c->iev.ibuf.pid == pid) 194ad7c548dSflorian break; 195ad7c548dSflorian } 196ad7c548dSflorian 197ad7c548dSflorian return (c); 198ad7c548dSflorian } 199ad7c548dSflorian 200ad7c548dSflorian void 201ad7c548dSflorian control_close(int fd) 202ad7c548dSflorian { 203ad7c548dSflorian struct ctl_conn *c; 204ad7c548dSflorian 205ad7c548dSflorian if ((c = control_connbyfd(fd)) == NULL) { 206ad7c548dSflorian log_warnx("%s: fd %d: not found", __func__, fd); 207ad7c548dSflorian return; 208ad7c548dSflorian } 209ad7c548dSflorian 2109cbf9e90Sclaudio imsgbuf_clear(&c->iev.ibuf); 211ad7c548dSflorian TAILQ_REMOVE(&ctl_conns, c, entry); 212ad7c548dSflorian 213ad7c548dSflorian event_del(&c->iev.ev); 214ad7c548dSflorian close(c->iev.ibuf.fd); 215ad7c548dSflorian 216ad7c548dSflorian /* Some file descriptors are available again. */ 217ad7c548dSflorian if (evtimer_pending(&control_state.evt, NULL)) { 218ad7c548dSflorian evtimer_del(&control_state.evt); 219ad7c548dSflorian event_add(&control_state.ev, NULL); 220ad7c548dSflorian } 221ad7c548dSflorian 222ad7c548dSflorian free(c); 223ad7c548dSflorian } 224ad7c548dSflorian 225ad7c548dSflorian void 226ad7c548dSflorian control_dispatch_imsg(int fd, short event, void *bula) 227ad7c548dSflorian { 228ad7c548dSflorian struct ctl_conn *c; 229ad7c548dSflorian struct imsg imsg; 230ad7c548dSflorian ssize_t n; 231ad7c548dSflorian int verbose; 232ad7c548dSflorian 233ad7c548dSflorian if ((c = control_connbyfd(fd)) == NULL) { 234ad7c548dSflorian log_warnx("%s: fd %d: not found", __func__, fd); 235ad7c548dSflorian return; 236ad7c548dSflorian } 237ad7c548dSflorian 238ad7c548dSflorian if (event & EV_READ) { 239668e5ba9Sclaudio if (imsgbuf_read(&c->iev.ibuf) != 1) { 240ad7c548dSflorian control_close(fd); 241ad7c548dSflorian return; 242ad7c548dSflorian } 243ad7c548dSflorian } 244ad7c548dSflorian if (event & EV_WRITE) { 245dd7efffeSclaudio if (imsgbuf_write(&c->iev.ibuf) == -1) { 246ad7c548dSflorian control_close(fd); 247ad7c548dSflorian return; 248ad7c548dSflorian } 249ad7c548dSflorian } 250ad7c548dSflorian 251ad7c548dSflorian for (;;) { 252ad7c548dSflorian if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) { 253ad7c548dSflorian control_close(fd); 254ad7c548dSflorian return; 255ad7c548dSflorian } 256ad7c548dSflorian if (n == 0) 257ad7c548dSflorian break; 258ad7c548dSflorian 259ad7c548dSflorian switch (imsg.hdr.type) { 260ad7c548dSflorian case IMSG_CTL_RELOAD: 261ad7c548dSflorian frontend_imsg_compose_main(imsg.hdr.type, 0, NULL, 0); 262ad7c548dSflorian break; 263ad7c548dSflorian case IMSG_CTL_LOG_VERBOSE: 264ad7c548dSflorian if (IMSG_DATA_SIZE(imsg) != sizeof(verbose)) 265ad7c548dSflorian break; 266ad7c548dSflorian c->iev.ibuf.pid = imsg.hdr.pid; 267ad7c548dSflorian /* Forward to all other processes. */ 268ad7c548dSflorian frontend_imsg_compose_main(imsg.hdr.type, imsg.hdr.pid, 269ad7c548dSflorian imsg.data, IMSG_DATA_SIZE(imsg)); 270ad7c548dSflorian frontend_imsg_compose_engine(imsg.hdr.type, 0, 271ad7c548dSflorian imsg.hdr.pid, imsg.data, IMSG_DATA_SIZE(imsg)); 272ad7c548dSflorian 273ad7c548dSflorian memcpy(&verbose, imsg.data, sizeof(verbose)); 274ad7c548dSflorian log_setverbose(verbose); 275ad7c548dSflorian break; 276ad7c548dSflorian case IMSG_CTL_SHOW_INTERFACE_INFO: 277ad7c548dSflorian if (IMSG_DATA_SIZE(imsg) != sizeof(uint32_t)) 278ad7c548dSflorian break; 279ad7c548dSflorian c->iev.ibuf.pid = imsg.hdr.pid; 280ad7c548dSflorian frontend_imsg_compose_engine(imsg.hdr.type, 0, 281ad7c548dSflorian imsg.hdr.pid, imsg.data, IMSG_DATA_SIZE(imsg)); 282ad7c548dSflorian break; 283ad7c548dSflorian case IMSG_CTL_SEND_REQUEST: 284ad7c548dSflorian if (IMSG_DATA_SIZE(imsg) != sizeof(uint32_t)) 285ad7c548dSflorian break; 286ad7c548dSflorian c->iev.ibuf.pid = imsg.hdr.pid; 287ad7c548dSflorian frontend_imsg_compose_engine(IMSG_REQUEST_REBOOT, 0, 288ad7c548dSflorian imsg.hdr.pid, imsg.data, IMSG_DATA_SIZE(imsg)); 289ad7c548dSflorian break; 290ad7c548dSflorian default: 291ad7c548dSflorian log_debug("%s: error handling imsg %d", __func__, 292ad7c548dSflorian imsg.hdr.type); 293ad7c548dSflorian break; 294ad7c548dSflorian } 295ad7c548dSflorian imsg_free(&imsg); 296ad7c548dSflorian } 297ad7c548dSflorian 298ad7c548dSflorian imsg_event_add(&c->iev); 299ad7c548dSflorian } 300ad7c548dSflorian 301ad7c548dSflorian int 302ad7c548dSflorian control_imsg_relay(struct imsg *imsg) 303ad7c548dSflorian { 304ad7c548dSflorian struct ctl_conn *c; 305ad7c548dSflorian 306ad7c548dSflorian if ((c = control_connbypid(imsg->hdr.pid)) == NULL) 307ad7c548dSflorian return (0); 308ad7c548dSflorian 309ad7c548dSflorian return (imsg_compose_event(&c->iev, imsg->hdr.type, 0, imsg->hdr.pid, 310ad7c548dSflorian -1, imsg->data, IMSG_DATA_SIZE(*imsg))); 311ad7c548dSflorian } 312