| File: | src/usr.sbin/ldapd/control.c |
| Warning: | line 237, column 7 Although the value stored to 'c' is used in the enclosing expression, the value is never actually read from 'c' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: control.c,v 1.18 2023/03/08 04:43:13 guenther Exp $ */ |
| 2 | |
| 3 | /* |
| 4 | * Copyright (c) 2010 Martin Hedenfalk <martin@bzero.se> |
| 5 | * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> |
| 6 | * |
| 7 | * Permission to use, copy, modify, and distribute this software for any |
| 8 | * purpose with or without fee is hereby granted, provided that the above |
| 9 | * copyright notice and this permission notice appear in all copies. |
| 10 | * |
| 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 18 | */ |
| 19 | |
| 20 | #include <sys/queue.h> |
| 21 | #include <sys/types.h> |
| 22 | #include <sys/stat.h> |
| 23 | #include <sys/socket.h> |
| 24 | #include <sys/un.h> |
| 25 | #include <sys/tree.h> |
| 26 | |
| 27 | #include <net/if.h> |
| 28 | |
| 29 | #include <errno(*__errno()).h> |
| 30 | #include <event.h> |
| 31 | #include <fcntl.h> |
| 32 | #include <signal.h> |
| 33 | #include <stdlib.h> |
| 34 | #include <string.h> |
| 35 | #include <unistd.h> |
| 36 | |
| 37 | #include "ldapd.h" |
| 38 | #include "log.h" |
| 39 | |
| 40 | #define CONTROL_BACKLOG5 5 |
| 41 | |
| 42 | struct ctl_connlist ctl_conns = TAILQ_HEAD_INITIALIZER(ctl_conns){ ((void *)0), &(ctl_conns).tqh_first }; |
| 43 | |
| 44 | struct ctl_conn *control_connbyfd(int); |
| 45 | void control_close(int, struct control_sock *); |
| 46 | static void control_imsgev(struct imsgev *iev, int code, struct imsg *imsg); |
| 47 | static void control_needfd(struct imsgev *iev); |
| 48 | |
| 49 | void |
| 50 | control_init(struct control_sock *cs) |
| 51 | { |
| 52 | struct sockaddr_un sun; |
| 53 | int fd; |
| 54 | mode_t old_umask, mode; |
| 55 | |
| 56 | if (cs->cs_name == NULL((void *)0)) |
| 57 | return; |
| 58 | |
| 59 | if ((fd = socket(AF_UNIX1, SOCK_STREAM1 | SOCK_NONBLOCK0x4000, 0)) == -1) |
| 60 | fatal("control_init: socket"); |
| 61 | |
| 62 | memset(&sun, 0, sizeof(sun)); |
| 63 | sun.sun_family = AF_UNIX1; |
| 64 | if (strlcpy(sun.sun_path, cs->cs_name, |
| 65 | sizeof(sun.sun_path)) >= sizeof(sun.sun_path)) |
| 66 | fatalx("control_init: name too long"); |
| 67 | |
| 68 | if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == 0) |
| 69 | fatalx("control socket already listening"); |
| 70 | |
| 71 | if (unlink(cs->cs_name) == -1 && errno(*__errno()) != ENOENT2) |
| 72 | fatal("control_init: unlink"); |
| 73 | |
| 74 | if (cs->cs_restricted) { |
| 75 | old_umask = umask(S_IXUSR0000100|S_IXGRP0000010|S_IXOTH0000001); |
| 76 | mode = S_IRUSR0000400|S_IWUSR0000200|S_IRGRP0000040|S_IWGRP0000020|S_IROTH0000004|S_IWOTH0000002; |
| 77 | } else { |
| 78 | old_umask = umask(S_IXUSR0000100|S_IXGRP0000010|S_IWOTH0000002|S_IROTH0000004|S_IXOTH0000001); |
| 79 | mode = S_IRUSR0000400|S_IWUSR0000200|S_IRGRP0000040|S_IWGRP0000020; |
| 80 | } |
| 81 | |
| 82 | if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { |
| 83 | (void)umask(old_umask); |
| 84 | fatal("control_init: bind"); |
| 85 | } |
| 86 | (void)umask(old_umask); |
| 87 | |
| 88 | if (chmod(cs->cs_name, mode) == -1) { |
| 89 | (void)unlink(cs->cs_name); |
| 90 | fatal("control_init: chmod"); |
| 91 | } |
| 92 | |
| 93 | cs->cs_fd = fd; |
| 94 | } |
| 95 | |
| 96 | void |
| 97 | control_listen(struct control_sock *cs) |
| 98 | { |
| 99 | if (cs->cs_name == NULL((void *)0)) |
| 100 | return; |
| 101 | |
| 102 | if (listen(cs->cs_fd, CONTROL_BACKLOG5) == -1) |
| 103 | fatal("control_listen: listen"); |
| 104 | |
| 105 | event_set(&cs->cs_ev, cs->cs_fd, EV_READ0x02, |
| 106 | control_accept, cs); |
| 107 | event_add(&cs->cs_ev, NULL((void *)0)); |
| 108 | evtimer_set(&cs->cs_evt, control_accept, cs)event_set(&cs->cs_evt, -1, 0, control_accept, cs); |
| 109 | } |
| 110 | |
| 111 | void |
| 112 | control_cleanup(struct control_sock *cs) |
| 113 | { |
| 114 | if (cs->cs_name == NULL((void *)0)) |
| 115 | return; |
| 116 | event_del(&cs->cs_ev); |
| 117 | event_del(&cs->cs_evt); |
| 118 | } |
| 119 | |
| 120 | void |
| 121 | control_accept(int listenfd, short event, void *arg) |
| 122 | { |
| 123 | struct control_sock *cs = arg; |
| 124 | int connfd; |
| 125 | socklen_t len; |
| 126 | struct sockaddr_un sun; |
| 127 | struct ctl_conn *c; |
| 128 | |
| 129 | event_add(&cs->cs_ev, NULL((void *)0)); |
| 130 | if ((event & EV_TIMEOUT0x01)) |
| 131 | return; |
| 132 | |
| 133 | len = sizeof(sun); |
| 134 | if ((connfd = accept_reserve(listenfd, |
| 135 | (struct sockaddr *)&sun, &len, FD_RESERVE8)) == -1) { |
| 136 | /* |
| 137 | * Pause accept if we are out of file descriptors, or |
| 138 | * libevent will haunt us here too. |
| 139 | */ |
| 140 | if (errno(*__errno()) == ENFILE23 || errno(*__errno()) == EMFILE24) { |
| 141 | struct timeval evtpause = { 1, 0 }; |
| 142 | |
| 143 | event_del(&cs->cs_ev); |
| 144 | evtimer_add(&cs->cs_evt, &evtpause)event_add(&cs->cs_evt, &evtpause); |
| 145 | } else if (errno(*__errno()) != EWOULDBLOCK35 && errno(*__errno()) != EINTR4) |
| 146 | log_warn("control_accept"); |
| 147 | return; |
| 148 | } |
| 149 | |
| 150 | if ((c = calloc(1, sizeof(*c))) == NULL((void *)0)) { |
| 151 | log_warn("control_accept"); |
| 152 | close(connfd); |
| 153 | return; |
| 154 | } |
| 155 | |
| 156 | log_debug("accepted control fd %d", connfd); |
| 157 | TAILQ_INSERT_TAIL(&ctl_conns, c, entry)do { (c)->entry.tqe_next = ((void *)0); (c)->entry.tqe_prev = (&ctl_conns)->tqh_last; *(&ctl_conns)->tqh_last = (c); (&ctl_conns)->tqh_last = &(c)->entry.tqe_next ; } while (0); |
| 158 | imsgev_init(&c->iev, connfd, cs, control_imsgev, control_needfd); |
| 159 | } |
| 160 | |
| 161 | struct ctl_conn * |
| 162 | control_connbyfd(int fd) |
| 163 | { |
| 164 | struct ctl_conn *c; |
| 165 | |
| 166 | TAILQ_FOREACH(c, &ctl_conns, entry)for((c) = ((&ctl_conns)->tqh_first); (c) != ((void *)0 ); (c) = ((c)->entry.tqe_next)) { |
| 167 | if (c->iev.ibuf.fd == fd) |
| 168 | break; |
| 169 | } |
| 170 | |
| 171 | return (c); |
| 172 | } |
| 173 | |
| 174 | void |
| 175 | control_close(int fd, struct control_sock *cs) |
| 176 | { |
| 177 | struct ctl_conn *c; |
| 178 | |
| 179 | if ((c = control_connbyfd(fd)) == NULL((void *)0)) { |
| 180 | log_warnx("control_close: fd %d: not found", fd); |
| 181 | return; |
| 182 | } |
| 183 | |
| 184 | log_debug("close control fd %d", c->iev.ibuf.fd); |
| 185 | TAILQ_REMOVE(&ctl_conns, c, entry)do { if (((c)->entry.tqe_next) != ((void *)0)) (c)->entry .tqe_next->entry.tqe_prev = (c)->entry.tqe_prev; else ( &ctl_conns)->tqh_last = (c)->entry.tqe_prev; *(c)-> entry.tqe_prev = (c)->entry.tqe_next; ; ; } while (0); |
| 186 | imsgev_clear(&c->iev); |
| 187 | |
| 188 | /* Some file descriptors are available again. */ |
| 189 | if (evtimer_pending(&cs->cs_evt, NULL)event_pending(&cs->cs_evt, 0x01, ((void *)0))) { |
| 190 | evtimer_del(&cs->cs_evt)event_del(&cs->cs_evt); |
| 191 | event_add(&cs->cs_ev, NULL((void *)0)); |
| 192 | } |
| 193 | |
| 194 | free(c); |
| 195 | } |
| 196 | |
| 197 | static int |
| 198 | send_stats(struct imsgev *iev) |
| 199 | { |
| 200 | struct namespace *ns; |
| 201 | const struct btree_stat *st; |
| 202 | struct ns_stat nss; |
| 203 | |
| 204 | imsgev_compose(iev, IMSG_CTL_STATS, 0, iev->ibuf.pid, -1, |
| 205 | &stats, sizeof(stats)); |
| 206 | |
| 207 | TAILQ_FOREACH(ns, &conf->namespaces, next)for((ns) = ((&conf->namespaces)->tqh_first); (ns) != ((void *)0); (ns) = ((ns)->next.tqe_next)) { |
| 208 | if (namespace_has_referrals(ns)) |
| 209 | continue; |
| 210 | memset(&nss, 0, sizeof(nss)); |
| 211 | strlcpy(nss.suffix, ns->suffix, sizeof(nss.suffix)); |
| 212 | if ((st = btree_stat(ns->data_db)) != NULL((void *)0)) |
| 213 | bcopy(st, &nss.data_stat, sizeof(nss.data_stat)); |
| 214 | |
| 215 | if ((st = btree_stat(ns->indx_db)) != NULL((void *)0)) |
| 216 | bcopy(st, &nss.indx_stat, sizeof(nss.indx_stat)); |
| 217 | |
| 218 | imsgev_compose(iev, IMSG_CTL_NSSTATS, 0, iev->ibuf.pid, -1, |
| 219 | &nss, sizeof(nss)); |
| 220 | } |
| 221 | |
| 222 | imsgev_compose(iev, IMSG_CTL_END, 0, iev->ibuf.pid, -1, NULL((void *)0), 0); |
| 223 | |
| 224 | return 0; |
| 225 | } |
| 226 | |
| 227 | static void |
| 228 | control_imsgev(struct imsgev *iev, int code, struct imsg *imsg) |
| 229 | { |
| 230 | struct control_sock *cs; |
| 231 | struct ctl_conn *c; |
| 232 | int fd, verbose; |
| 233 | |
| 234 | cs = iev->data; |
| 235 | fd = iev->ibuf.fd; |
| 236 | |
| 237 | if ((c = control_connbyfd(fd)) == NULL((void *)0)) { |
Although the value stored to 'c' is used in the enclosing expression, the value is never actually read from 'c' | |
| 238 | log_warnx("%s: fd %d: not found", __func__, fd); |
| 239 | return; |
| 240 | } |
| 241 | |
| 242 | if (code != IMSGEV_IMSG0) { |
| 243 | control_close(fd, cs); |
| 244 | return; |
| 245 | } |
| 246 | |
| 247 | log_debug("%s: got imsg %d on fd %d", __func__, imsg->hdr.type, fd); |
| 248 | switch (imsg->hdr.type) { |
| 249 | case IMSG_CTL_STATS: |
| 250 | if (send_stats(iev) == -1) { |
| 251 | log_debug("%s: failed to send statistics", __func__); |
| 252 | control_close(fd, cs); |
| 253 | } |
| 254 | break; |
| 255 | case IMSG_CTL_LOG_VERBOSE: |
| 256 | if (imsg->hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(verbose)) |
| 257 | break; |
| 258 | |
| 259 | bcopy(imsg->data, &verbose, sizeof(verbose)); |
| 260 | imsgev_compose(iev_ldapd, IMSG_CTL_LOG_VERBOSE, 0, 0, -1, |
| 261 | &verbose, sizeof(verbose)); |
| 262 | |
| 263 | log_setverbose(verbose); |
| 264 | break; |
| 265 | default: |
| 266 | log_warnx("%s: unexpected imsg %d", __func__, imsg->hdr.type); |
| 267 | break; |
| 268 | } |
| 269 | } |
| 270 | |
| 271 | void |
| 272 | control_needfd(struct imsgev *iev) |
| 273 | { |
| 274 | fatal("should never need an fd for control messages"); |
| 275 | } |
| 276 | |
| 277 | int |
| 278 | control_close_any(struct control_sock *cs) |
| 279 | { |
| 280 | struct ctl_conn *c; |
| 281 | |
| 282 | c = TAILQ_FIRST(&ctl_conns)((&ctl_conns)->tqh_first); |
| 283 | if (c != NULL((void *)0)) { |
| 284 | log_warn("closing oldest control connection"); |
| 285 | control_close(c->iev.ibuf.fd, cs); |
| 286 | return (0); |
| 287 | } |
| 288 | log_warn("no control connections to close"); |
| 289 | return (-1); |
| 290 | } |