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.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_BACKLOG 5
41
42 struct ctl_connlist ctl_conns = TAILQ_HEAD_INITIALIZER(ctl_conns);
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
control_init(struct control_sock * cs)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)
57 return;
58
59 if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0)) == -1)
60 fatal("control_init: socket");
61
62 memset(&sun, 0, sizeof(sun));
63 sun.sun_family = AF_UNIX;
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 != ENOENT)
72 fatal("control_init: unlink");
73
74 if (cs->cs_restricted) {
75 old_umask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
76 mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
77 } else {
78 old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
79 mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP;
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
control_listen(struct control_sock * cs)97 control_listen(struct control_sock *cs)
98 {
99 if (cs->cs_name == NULL)
100 return;
101
102 if (listen(cs->cs_fd, CONTROL_BACKLOG) == -1)
103 fatal("control_listen: listen");
104
105 event_set(&cs->cs_ev, cs->cs_fd, EV_READ,
106 control_accept, cs);
107 event_add(&cs->cs_ev, NULL);
108 evtimer_set(&cs->cs_evt, control_accept, cs);
109 }
110
111 void
control_cleanup(struct control_sock * cs)112 control_cleanup(struct control_sock *cs)
113 {
114 if (cs->cs_name == NULL)
115 return;
116 event_del(&cs->cs_ev);
117 event_del(&cs->cs_evt);
118 }
119
120 void
control_accept(int listenfd,short event,void * arg)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);
130 if ((event & EV_TIMEOUT))
131 return;
132
133 len = sizeof(sun);
134 if ((connfd = accept_reserve(listenfd,
135 (struct sockaddr *)&sun, &len, FD_RESERVE)) == -1) {
136 /*
137 * Pause accept if we are out of file descriptors, or
138 * libevent will haunt us here too.
139 */
140 if (errno == ENFILE || errno == EMFILE) {
141 struct timeval evtpause = { 1, 0 };
142
143 event_del(&cs->cs_ev);
144 evtimer_add(&cs->cs_evt, &evtpause);
145 } else if (errno != EWOULDBLOCK && errno != EINTR)
146 log_warn("control_accept");
147 return;
148 }
149
150 if ((c = calloc(1, sizeof(*c))) == NULL) {
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);
158 imsgev_init(&c->iev, connfd, cs, control_imsgev, control_needfd);
159 }
160
161 struct ctl_conn *
control_connbyfd(int fd)162 control_connbyfd(int fd)
163 {
164 struct ctl_conn *c;
165
166 TAILQ_FOREACH(c, &ctl_conns, entry) {
167 if (c->iev.ibuf.fd == fd)
168 break;
169 }
170
171 return (c);
172 }
173
174 void
control_close(int fd,struct control_sock * cs)175 control_close(int fd, struct control_sock *cs)
176 {
177 struct ctl_conn *c;
178
179 if ((c = control_connbyfd(fd)) == NULL) {
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);
186 imsgev_clear(&c->iev);
187
188 /* Some file descriptors are available again. */
189 if (evtimer_pending(&cs->cs_evt, NULL)) {
190 evtimer_del(&cs->cs_evt);
191 event_add(&cs->cs_ev, NULL);
192 }
193
194 free(c);
195 }
196
197 static int
send_stats(struct imsgev * iev)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) {
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)
213 bcopy(st, &nss.data_stat, sizeof(nss.data_stat));
214
215 if ((st = btree_stat(ns->indx_db)) != NULL)
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, 0);
223
224 return 0;
225 }
226
227 static void
control_imsgev(struct imsgev * iev,int code,struct imsg * imsg)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) {
238 log_warnx("%s: fd %d: not found", __func__, fd);
239 return;
240 }
241
242 if (code != IMSGEV_IMSG) {
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_SIZE + 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
control_needfd(struct imsgev * iev)272 control_needfd(struct imsgev *iev)
273 {
274 fatal("should never need an fd for control messages");
275 }
276
277 int
control_close_any(struct control_sock * cs)278 control_close_any(struct control_sock *cs)
279 {
280 struct ctl_conn *c;
281
282 c = TAILQ_FIRST(&ctl_conns);
283 if (c != NULL) {
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 }
291