xref: /openbsd-src/usr.sbin/ldapd/control.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: control.c,v 1.13 2016/01/17 08:13:34 landry 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 
39 #define	CONTROL_BACKLOG	5
40 
41 struct ctl_connlist ctl_conns;
42 
43 struct ctl_conn	*control_connbyfd(int);
44 void		 control_close(int, struct control_sock *);
45 static void	 control_imsgev(struct imsgev *iev, int code, struct imsg *imsg);
46 static void	 control_needfd(struct imsgev *iev);
47 
48 void
49 control_init(struct control_sock *cs)
50 {
51 	struct sockaddr_un	 sun;
52 	int			 fd;
53 	mode_t			 old_umask, mode;
54 
55 	if (cs->cs_name == NULL)
56 		return;
57 
58 	if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0)) == -1)
59 		fatal("control_init: socket");
60 
61 	memset(&sun, 0, sizeof(sun));
62 	sun.sun_family = AF_UNIX;
63 	if (strlcpy(sun.sun_path, cs->cs_name,
64 	    sizeof(sun.sun_path)) >= sizeof(sun.sun_path))
65 		fatalx("control_init: name too long");
66 
67 	if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == 0)
68 		fatalx("control socket already listening");
69 
70 	if (unlink(cs->cs_name) == -1 && errno != ENOENT)
71 		fatal("control_init: unlink");
72 
73 	if (cs->cs_restricted) {
74 		old_umask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
75 		mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
76 	} else {
77 		old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
78 		mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP;
79 	}
80 
81 	if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
82 		(void)umask(old_umask);
83 		fatal("control_init: bind");
84 	}
85 	(void)umask(old_umask);
86 
87 	if (chmod(cs->cs_name, mode) == -1) {
88 		(void)unlink(cs->cs_name);
89 		fatal("control_init: chmod");
90 	}
91 
92 	cs->cs_fd = fd;
93 }
94 
95 void
96 control_listen(struct control_sock *cs)
97 {
98 	if (cs->cs_name == NULL)
99 		return;
100 
101 	if (listen(cs->cs_fd, CONTROL_BACKLOG) == -1)
102 		fatal("control_listen: listen");
103 
104 	event_set(&cs->cs_ev, cs->cs_fd, EV_READ,
105 	    control_accept, cs);
106 	event_add(&cs->cs_ev, NULL);
107 	evtimer_set(&cs->cs_evt, control_accept, cs);
108 }
109 
110 void
111 control_cleanup(struct control_sock *cs)
112 {
113 	if (cs->cs_name == NULL)
114 		return;
115 	event_del(&cs->cs_ev);
116 	event_del(&cs->cs_evt);
117 }
118 
119 /* ARGSUSED */
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);
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 *
162 control_connbyfd(int fd)
163 {
164 	struct ctl_conn	*c;
165 
166 	for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->iev.ibuf.fd != fd;
167 	    c = TAILQ_NEXT(c, entry))
168 		;	/* nothing */
169 
170 	return (c);
171 }
172 
173 void
174 control_close(int fd, struct control_sock *cs)
175 {
176 	struct ctl_conn	*c;
177 
178 	if ((c = control_connbyfd(fd)) == NULL) {
179 		log_warnx("control_close: fd %d: not found", fd);
180 		return;
181 	}
182 
183 	log_debug("close control fd %d", c->iev.ibuf.fd);
184 	TAILQ_REMOVE(&ctl_conns, c, entry);
185 	imsgev_clear(&c->iev);
186 
187 	/* Some file descriptors are available again. */
188 	if (evtimer_pending(&cs->cs_evt, NULL)) {
189 		evtimer_del(&cs->cs_evt);
190 		event_add(&cs->cs_ev, NULL);
191 	}
192 
193 	free(c);
194 }
195 
196 static int
197 send_stats(struct imsgev *iev)
198 {
199 	struct namespace	*ns;
200 	const struct btree_stat	*st;
201 	struct ns_stat		 nss;
202 
203 	imsgev_compose(iev, IMSG_CTL_STATS, 0, iev->ibuf.pid, -1,
204 	    &stats, sizeof(stats));
205 
206 	TAILQ_FOREACH(ns, &conf->namespaces, next) {
207 		if (namespace_has_referrals(ns))
208 			continue;
209 		memset(&nss, 0, sizeof(nss));
210 		strlcpy(nss.suffix, ns->suffix, sizeof(nss.suffix));
211 		if ((st = btree_stat(ns->data_db)) != NULL)
212 			bcopy(st, &nss.data_stat, sizeof(nss.data_stat));
213 
214 		if ((st = btree_stat(ns->indx_db)) != NULL)
215 			bcopy(st, &nss.indx_stat, sizeof(nss.indx_stat));
216 
217 		imsgev_compose(iev, IMSG_CTL_NSSTATS, 0, iev->ibuf.pid, -1,
218 		    &nss, sizeof(nss));
219 	}
220 
221 	imsgev_compose(iev, IMSG_CTL_END, 0, iev->ibuf.pid, -1, NULL, 0);
222 
223 	return 0;
224 }
225 
226 static void
227 control_imsgev(struct imsgev *iev, int code, struct imsg *imsg)
228 {
229 	struct control_sock	*cs;
230 	struct ctl_conn		*c;
231 	int			 fd, verbose;
232 
233 	cs = iev->data;
234 	fd = iev->ibuf.fd;
235 
236 	if ((c = control_connbyfd(fd)) == NULL) {
237 		log_warnx("%s: fd %d: not found", __func__, fd);
238 		return;
239 	}
240 
241 	if (code != IMSGEV_IMSG) {
242 		control_close(fd, cs);
243 		return;
244 	}
245 
246 	log_debug("%s: got imsg %d on fd %d", __func__, imsg->hdr.type, fd);
247 	switch (imsg->hdr.type) {
248 	case IMSG_CTL_STATS:
249 		if (send_stats(iev) == -1) {
250 			log_debug("%s: failed to send statistics", __func__);
251 			control_close(fd, cs);
252 		}
253 		break;
254 	case IMSG_CTL_LOG_VERBOSE:
255 		if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(verbose))
256 			break;
257 
258 		bcopy(imsg->data, &verbose, sizeof(verbose));
259 		imsgev_compose(iev_ldapd, IMSG_CTL_LOG_VERBOSE, 0, 0, -1,
260 		    &verbose, sizeof(verbose));
261 
262 		log_verbose(verbose);
263 		break;
264 	default:
265 		log_warnx("%s: unexpected imsg %d", __func__, imsg->hdr.type);
266 		break;
267 	}
268 }
269 
270 void
271 control_needfd(struct imsgev *iev)
272 {
273 	fatal("should never need an fd for control messages");
274 }
275 
276 int
277 control_close_any(struct control_sock *cs)
278 {
279 	struct ctl_conn		*c;
280 
281 	c = TAILQ_FIRST(&ctl_conns);
282 	if (c != NULL) {
283 		log_warn("closing oldest control connection");
284 		control_close(c->iev.ibuf.fd, cs);
285 		return (0);
286 	}
287 	log_warn("no control connections to close");
288 	return (-1);
289 }
290