1*0e59d0d1Sclaudio /* $OpenBSD: control.c,v 1.23 2024/11/21 13:35:20 claudio Exp $ */ 2018cebfbSflorian 3018cebfbSflorian /* 4018cebfbSflorian * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 5018cebfbSflorian * 6018cebfbSflorian * Permission to use, copy, modify, and distribute this software for any 7018cebfbSflorian * purpose with or without fee is hereby granted, provided that the above 8018cebfbSflorian * copyright notice and this permission notice appear in all copies. 9018cebfbSflorian * 10018cebfbSflorian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11018cebfbSflorian * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12018cebfbSflorian * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13018cebfbSflorian * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14018cebfbSflorian * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15018cebfbSflorian * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16018cebfbSflorian * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17018cebfbSflorian */ 18018cebfbSflorian #include <sys/types.h> 19018cebfbSflorian #include <sys/queue.h> 20018cebfbSflorian #include <sys/stat.h> 21018cebfbSflorian #include <sys/socket.h> 225ec49af2Sflorian #include <sys/time.h> 23018cebfbSflorian #include <sys/un.h> 24018cebfbSflorian 2528ba4729Sflorian #include <net/route.h> 2628ba4729Sflorian 27018cebfbSflorian #include <errno.h> 28018cebfbSflorian #include <event.h> 29018cebfbSflorian #include <imsg.h> 30018cebfbSflorian #include <stdlib.h> 31018cebfbSflorian #include <string.h> 32018cebfbSflorian #include <unistd.h> 33018cebfbSflorian 3458b5b9b8Sflorian #include "log.h" 35018cebfbSflorian #include "unwind.h" 36018cebfbSflorian #include "control.h" 37018cebfbSflorian #include "frontend.h" 382b821978Sflorian #include "resolver.h" 39018cebfbSflorian 40018cebfbSflorian #define CONTROL_BACKLOG 5 41018cebfbSflorian 423538560bSflorian struct { 433538560bSflorian struct event ev; 443538560bSflorian struct event evt; 453538560bSflorian int fd; 463538560bSflorian } control_state = {.fd = -1}; 473538560bSflorian 483538560bSflorian struct ctl_conn { 493538560bSflorian TAILQ_ENTRY(ctl_conn) entry; 503538560bSflorian struct imsgev iev; 513538560bSflorian }; 523538560bSflorian 533538560bSflorian TAILQ_HEAD(ctl_conns, ctl_conn) ctl_conns = TAILQ_HEAD_INITIALIZER(ctl_conns); 543538560bSflorian 55018cebfbSflorian struct ctl_conn *control_connbyfd(int); 56018cebfbSflorian struct ctl_conn *control_connbypid(pid_t); 57018cebfbSflorian void control_close(int); 58018cebfbSflorian 59018cebfbSflorian int 60018cebfbSflorian control_init(char *path) 61018cebfbSflorian { 62018cebfbSflorian struct sockaddr_un sun; 63018cebfbSflorian int fd; 64018cebfbSflorian mode_t old_umask; 65018cebfbSflorian 66018cebfbSflorian if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 67018cebfbSflorian 0)) == -1) { 68018cebfbSflorian log_warn("%s: socket", __func__); 69018cebfbSflorian return (-1); 70018cebfbSflorian } 71018cebfbSflorian 72018cebfbSflorian memset(&sun, 0, sizeof(sun)); 73018cebfbSflorian sun.sun_family = AF_UNIX; 74018cebfbSflorian strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); 75018cebfbSflorian 76018cebfbSflorian if (unlink(path) == -1) 77018cebfbSflorian if (errno != ENOENT) { 78018cebfbSflorian log_warn("%s: unlink %s", __func__, path); 79018cebfbSflorian close(fd); 80018cebfbSflorian return (-1); 81018cebfbSflorian } 82018cebfbSflorian 83018cebfbSflorian old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); 84018cebfbSflorian if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { 85018cebfbSflorian log_warn("%s: bind: %s", __func__, path); 86018cebfbSflorian close(fd); 87018cebfbSflorian umask(old_umask); 88018cebfbSflorian return (-1); 89018cebfbSflorian } 90018cebfbSflorian umask(old_umask); 91018cebfbSflorian 92bb81f7e1Sflorian if (chmod(path, 93bb81f7e1Sflorian S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) == -1) { 94018cebfbSflorian log_warn("%s: chmod", __func__); 95018cebfbSflorian close(fd); 96018cebfbSflorian (void)unlink(path); 97018cebfbSflorian return (-1); 98018cebfbSflorian } 99018cebfbSflorian 100018cebfbSflorian return (fd); 101018cebfbSflorian } 102018cebfbSflorian 103018cebfbSflorian int 1043538560bSflorian control_listen(int fd) 105018cebfbSflorian { 1063538560bSflorian if (control_state.fd != -1) 1073538560bSflorian fatalx("%s: received unexpected controlsock", __func__); 1083538560bSflorian 1093538560bSflorian control_state.fd = fd; 110018cebfbSflorian if (listen(control_state.fd, CONTROL_BACKLOG) == -1) { 111018cebfbSflorian log_warn("%s: listen", __func__); 112018cebfbSflorian return (-1); 113018cebfbSflorian } 114018cebfbSflorian 115018cebfbSflorian event_set(&control_state.ev, control_state.fd, EV_READ, 116018cebfbSflorian control_accept, NULL); 117018cebfbSflorian event_add(&control_state.ev, NULL); 118018cebfbSflorian evtimer_set(&control_state.evt, control_accept, NULL); 119018cebfbSflorian 120018cebfbSflorian return (0); 121018cebfbSflorian } 122018cebfbSflorian 123018cebfbSflorian void 124018cebfbSflorian control_accept(int listenfd, short event, void *bula) 125018cebfbSflorian { 126018cebfbSflorian int connfd; 127018cebfbSflorian socklen_t len; 128018cebfbSflorian struct sockaddr_un sun; 129018cebfbSflorian struct ctl_conn *c; 130018cebfbSflorian 131018cebfbSflorian event_add(&control_state.ev, NULL); 132018cebfbSflorian if ((event & EV_TIMEOUT)) 133018cebfbSflorian return; 134018cebfbSflorian 135018cebfbSflorian len = sizeof(sun); 136018cebfbSflorian if ((connfd = accept4(listenfd, (struct sockaddr *)&sun, &len, 137018cebfbSflorian SOCK_CLOEXEC | SOCK_NONBLOCK)) == -1) { 138018cebfbSflorian /* 139018cebfbSflorian * Pause accept if we are out of file descriptors, or 140018cebfbSflorian * libevent will haunt us here too. 141018cebfbSflorian */ 142018cebfbSflorian if (errno == ENFILE || errno == EMFILE) { 143018cebfbSflorian struct timeval evtpause = { 1, 0 }; 144018cebfbSflorian 145018cebfbSflorian event_del(&control_state.ev); 146018cebfbSflorian evtimer_add(&control_state.evt, &evtpause); 147018cebfbSflorian } else if (errno != EWOULDBLOCK && errno != EINTR && 148018cebfbSflorian errno != ECONNABORTED) 149018cebfbSflorian log_warn("%s: accept4", __func__); 150018cebfbSflorian return; 151018cebfbSflorian } 152018cebfbSflorian 153018cebfbSflorian if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) { 154018cebfbSflorian log_warn("%s: calloc", __func__); 155018cebfbSflorian close(connfd); 156018cebfbSflorian return; 157018cebfbSflorian } 158018cebfbSflorian 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 } 165018cebfbSflorian c->iev.handler = control_dispatch_imsg; 166018cebfbSflorian c->iev.events = EV_READ; 167bb81f7e1Sflorian event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events, c->iev.handler, 168bb81f7e1Sflorian &c->iev); 169018cebfbSflorian event_add(&c->iev.ev, NULL); 170018cebfbSflorian 171018cebfbSflorian TAILQ_INSERT_TAIL(&ctl_conns, c, entry); 172018cebfbSflorian } 173018cebfbSflorian 174018cebfbSflorian struct ctl_conn * 175018cebfbSflorian control_connbyfd(int fd) 176018cebfbSflorian { 177018cebfbSflorian struct ctl_conn *c; 178018cebfbSflorian 179018cebfbSflorian TAILQ_FOREACH(c, &ctl_conns, entry) { 180018cebfbSflorian if (c->iev.ibuf.fd == fd) 181018cebfbSflorian break; 182018cebfbSflorian } 183018cebfbSflorian 184018cebfbSflorian return (c); 185018cebfbSflorian } 186018cebfbSflorian 187018cebfbSflorian struct ctl_conn * 188018cebfbSflorian control_connbypid(pid_t pid) 189018cebfbSflorian { 190018cebfbSflorian struct ctl_conn *c; 191018cebfbSflorian 192018cebfbSflorian TAILQ_FOREACH(c, &ctl_conns, entry) { 193018cebfbSflorian if (c->iev.ibuf.pid == pid) 194018cebfbSflorian break; 195018cebfbSflorian } 196018cebfbSflorian 197018cebfbSflorian return (c); 198018cebfbSflorian } 199018cebfbSflorian 200018cebfbSflorian void 201018cebfbSflorian control_close(int fd) 202018cebfbSflorian { 203018cebfbSflorian struct ctl_conn *c; 204018cebfbSflorian 205018cebfbSflorian if ((c = control_connbyfd(fd)) == NULL) { 206018cebfbSflorian log_warnx("%s: fd %d: not found", __func__, fd); 207018cebfbSflorian return; 208018cebfbSflorian } 209018cebfbSflorian 2109cbf9e90Sclaudio imsgbuf_clear(&c->iev.ibuf); 211018cebfbSflorian TAILQ_REMOVE(&ctl_conns, c, entry); 212018cebfbSflorian 213018cebfbSflorian event_del(&c->iev.ev); 214018cebfbSflorian close(c->iev.ibuf.fd); 215018cebfbSflorian 216018cebfbSflorian /* Some file descriptors are available again. */ 217018cebfbSflorian if (evtimer_pending(&control_state.evt, NULL)) { 218018cebfbSflorian evtimer_del(&control_state.evt); 219018cebfbSflorian event_add(&control_state.ev, NULL); 220018cebfbSflorian } 221018cebfbSflorian 222018cebfbSflorian free(c); 223018cebfbSflorian } 224018cebfbSflorian 225018cebfbSflorian void 226018cebfbSflorian control_dispatch_imsg(int fd, short event, void *bula) 227018cebfbSflorian { 228018cebfbSflorian struct ctl_conn *c; 229018cebfbSflorian struct imsg imsg; 230018cebfbSflorian ssize_t n; 231018cebfbSflorian int verbose; 2323a1cc939Ssolene uid_t euid; 2333a1cc939Ssolene gid_t egid; 234018cebfbSflorian 235018cebfbSflorian if ((c = control_connbyfd(fd)) == NULL) { 236018cebfbSflorian log_warnx("%s: fd %d: not found", __func__, fd); 237018cebfbSflorian return; 238018cebfbSflorian } 239018cebfbSflorian 240018cebfbSflorian if (event & EV_READ) { 241668e5ba9Sclaudio if (imsgbuf_read(&c->iev.ibuf) != 1) { 242018cebfbSflorian control_close(fd); 243018cebfbSflorian return; 244018cebfbSflorian } 245018cebfbSflorian } 246018cebfbSflorian if (event & EV_WRITE) { 247dd7efffeSclaudio if (imsgbuf_write(&c->iev.ibuf) == -1) { 248018cebfbSflorian control_close(fd); 249018cebfbSflorian return; 250018cebfbSflorian } 251018cebfbSflorian } 252018cebfbSflorian 2533a1cc939Ssolene if (getpeereid(fd, &euid, &egid) == -1) { 2543a1cc939Ssolene control_close(fd); 2553a1cc939Ssolene return; 2563a1cc939Ssolene } 2573a1cc939Ssolene 258018cebfbSflorian for (;;) { 259018cebfbSflorian if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) { 260018cebfbSflorian control_close(fd); 261018cebfbSflorian return; 262018cebfbSflorian } 263018cebfbSflorian if (n == 0) 264018cebfbSflorian break; 265018cebfbSflorian 266018cebfbSflorian switch (imsg.hdr.type) { 2673a1cc939Ssolene case IMSG_CTL_LOG_VERBOSE: 2683a1cc939Ssolene case IMSG_CTL_RELOAD: 2693a1cc939Ssolene if (euid != 0) { 2703a1cc939Ssolene imsg_free(&imsg); 2713a1cc939Ssolene control_close(fd); 2723a1cc939Ssolene return; 2733a1cc939Ssolene } 2743a1cc939Ssolene break; 2753a1cc939Ssolene default: 2763a1cc939Ssolene break; 2773a1cc939Ssolene } 2783a1cc939Ssolene 279b121c2f3Sflorian c->iev.ibuf.pid = imsg.hdr.pid; 2803a1cc939Ssolene switch (imsg.hdr.type) { 281018cebfbSflorian case IMSG_CTL_RELOAD: 282b121c2f3Sflorian frontend_imsg_compose_main(imsg.hdr.type, imsg.hdr.pid, 283b121c2f3Sflorian NULL, 0); 284018cebfbSflorian break; 285018cebfbSflorian case IMSG_CTL_LOG_VERBOSE: 286a9155f32Sflorian if (IMSG_DATA_SIZE(imsg) != sizeof(verbose)) 287018cebfbSflorian break; 288018cebfbSflorian 289018cebfbSflorian /* Forward to all other processes. */ 290018cebfbSflorian frontend_imsg_compose_main(imsg.hdr.type, imsg.hdr.pid, 291a9155f32Sflorian imsg.data, IMSG_DATA_SIZE(imsg)); 292018cebfbSflorian frontend_imsg_compose_resolver(imsg.hdr.type, 293a9155f32Sflorian imsg.hdr.pid, imsg.data, IMSG_DATA_SIZE(imsg)); 294018cebfbSflorian 295018cebfbSflorian memcpy(&verbose, imsg.data, sizeof(verbose)); 296018cebfbSflorian log_setverbose(verbose); 297018cebfbSflorian break; 298018cebfbSflorian case IMSG_CTL_STATUS: 29915fe126bSflorian case IMSG_CTL_AUTOCONF: 300c071f090Sflorian case IMSG_CTL_MEM: 301f6a28683Sotto if (IMSG_DATA_SIZE(imsg) != 0) 3022b821978Sflorian break; 303b121c2f3Sflorian frontend_imsg_compose_resolver(imsg.hdr.type, 304b121c2f3Sflorian imsg.hdr.pid, NULL, 0); 305018cebfbSflorian break; 306018cebfbSflorian default: 307018cebfbSflorian log_debug("%s: error handling imsg %d", __func__, 308018cebfbSflorian imsg.hdr.type); 309018cebfbSflorian break; 310018cebfbSflorian } 311018cebfbSflorian imsg_free(&imsg); 312018cebfbSflorian } 313018cebfbSflorian 314018cebfbSflorian imsg_event_add(&c->iev); 315018cebfbSflorian } 316018cebfbSflorian 317018cebfbSflorian int 318018cebfbSflorian control_imsg_relay(struct imsg *imsg) 319018cebfbSflorian { 320018cebfbSflorian struct ctl_conn *c; 321018cebfbSflorian 322018cebfbSflorian if ((c = control_connbypid(imsg->hdr.pid)) == NULL) 323018cebfbSflorian return (0); 324018cebfbSflorian 325018cebfbSflorian return (imsg_compose_event(&c->iev, imsg->hdr.type, 0, imsg->hdr.pid, 326a9155f32Sflorian -1, imsg->data, IMSG_DATA_SIZE(*imsg))); 327018cebfbSflorian } 328