xref: /openbsd-src/usr.sbin/ldapd/conn.c (revision 0b7734b3d77bb9b21afec6f4621cae6c805dbd45)
1 /*	$OpenBSD: conn.c,v 1.13 2016/05/01 00:32:37 jmatthew Exp $ */
2 
3 /*
4  * Copyright (c) 2009, 2010 Martin Hedenfalk <martin@bzero.se>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/queue.h>
20 #include <sys/types.h>
21 
22 #include <stdlib.h>
23 #include <errno.h>
24 #include <unistd.h>
25 
26 #include "ldapd.h"
27 
28 int			 conn_dispatch(struct conn *conn);
29 int			 conn_tls_init(struct conn *);
30 unsigned long		 ldap_application(struct ber_element *elm);
31 
32 struct conn_list	 conn_list;
33 
34 unsigned long
35 ldap_application(struct ber_element *elm)
36 {
37 	return BER_TYPE_OCTETSTRING;
38 }
39 
40 void
41 request_free(struct request *req)
42 {
43 	if (req->root != NULL)
44 		ber_free_elements(req->root);
45 	free(req);
46 }
47 
48 void
49 conn_close(struct conn *conn)
50 {
51 	struct search	*search, *next;
52 	struct listener *l = conn->listener;
53 
54 	log_debug("closing connection %d", conn->fd);
55 
56 	/* Cancel any ongoing searches on this connection. */
57 	for (search = TAILQ_FIRST(&conn->searches); search; search = next) {
58 		next = TAILQ_NEXT(search, next);
59 		search_close(search);
60 	}
61 
62 	/* Cancel any queued requests on this connection. */
63 	namespace_cancel_conn(conn);
64 
65 	tls_free(conn->tls);
66 
67 	TAILQ_REMOVE(&conn_list, conn, next);
68 	ber_free(&conn->ber);
69 	if (conn->bev != NULL)
70 		bufferevent_free(conn->bev);
71 	close(conn->fd);
72 
73 	/* Some file descriptors are available again. */
74 	if (evtimer_pending(&l->evt, NULL)) {
75 		evtimer_del(&l->evt);
76 		event_add(&l->ev, NULL);
77 	}
78 
79 	free(conn->binddn);
80 	free(conn->pending_binddn);
81 	free(conn);
82 
83 	--stats.conns;
84 }
85 
86 /* Marks a connection for disconnect. The connection will be closed when
87  * any remaining data has been flushed to the socket.
88  */
89 void
90 conn_disconnect(struct conn *conn)
91 {
92 	conn->disconnect = 1;
93 	bufferevent_enable(conn->bev, EV_WRITE);
94 }
95 
96 void
97 request_dispatch(struct request *req)
98 {
99 	unsigned long		 i;
100 	struct {
101 		unsigned long	 type;
102 		int (*fn)(struct request *);
103 	} requests[] = {
104 		{ LDAP_REQ_SEARCH,	ldap_search },
105 		{ LDAP_REQ_BIND,	ldap_bind },
106 		{ LDAP_REQ_COMPARE,	ldap_compare },
107 		{ LDAP_REQ_ADD,		ldap_add },
108 		{ LDAP_REQ_UNBIND_30,	ldap_unbind },
109 		{ LDAP_REQ_MODIFY,	ldap_modify },
110 		{ LDAP_REQ_ABANDON_30,	ldap_abandon },
111 		{ LDAP_REQ_DELETE_30,	ldap_delete },
112 		{ LDAP_REQ_EXTENDED,	ldap_extended },
113 		{ 0,			NULL }
114 	};
115 
116 	/* RFC4511, section 4.2.1 says we shouldn't process other requests
117 	 * while binding. A bind operation can, however, be aborted by sending
118 	 * another bind operation.
119 	 */
120 	if (req->conn->bind_req != NULL && req->type != LDAP_REQ_BIND) {
121 		log_warnx("got request while bind in progress");
122 		ldap_respond(req, LDAP_SASL_BIND_IN_PROGRESS);
123 		return;
124 	}
125 
126 	for (i = 0; requests[i].fn != NULL; i++) {
127 		if (requests[i].type == req->type) {
128 			requests[i].fn(req);
129 			break;
130 		}
131 	}
132 
133 	if (requests[i].fn == NULL) {
134 		log_warnx("unhandled request %d (not implemented)", req->type);
135 		ldap_respond(req, LDAP_PROTOCOL_ERROR);
136 	}
137 }
138 
139 int
140 conn_dispatch(struct conn *conn)
141 {
142 	int			 class;
143 	struct request		*req;
144 	u_char			*rptr;
145 
146 	++stats.requests;
147 
148 	if ((req = calloc(1, sizeof(*req))) == NULL) {
149 		log_warn("calloc");
150 		conn_disconnect(conn);
151 		return -1;
152 	}
153 
154 	req->conn = conn;
155 	rptr = conn->ber.br_rptr;	/* save where we start reading */
156 
157 	if ((req->root = ber_read_elements(&conn->ber, NULL)) == NULL) {
158 		if (errno != ECANCELED) {
159 			log_warnx("protocol error");
160 			hexdump(rptr, conn->ber.br_rend - rptr,
161 			    "failed to parse request from %zi bytes:",
162 			    conn->ber.br_rend - rptr);
163 			conn_disconnect(conn);
164 		}
165 		request_free(req);
166 		return -1;
167 	}
168 	log_debug("consumed %d bytes", conn->ber.br_rptr - rptr);
169 
170 	/* Read message id and request type.
171 	 */
172 	if (ber_scanf_elements(req->root, "{ite",
173 	    &req->msgid, &class, &req->type, &req->op) != 0) {
174 		log_warnx("protocol error");
175 		ldap_debug_elements(req->root, -1,
176 		    "received invalid request on fd %d", conn->fd);
177 		conn_disconnect(conn);
178 		request_free(req);
179 		return -1;
180 	}
181 
182 	ldap_debug_elements(req->root, req->type,
183 	    "received request on fd %d", conn->fd);
184 
185 	log_debug("got request type %d, id %lld", req->type, req->msgid);
186 	request_dispatch(req);
187 	return 0;
188 }
189 
190 void
191 conn_read(struct bufferevent *bev, void *data)
192 {
193 	size_t			 nused = 0;
194 	struct conn		*conn = data;
195 	struct evbuffer		*input;
196 
197 	input = EVBUFFER_INPUT(bev);
198 	ber_set_readbuf(&conn->ber,
199 	    EVBUFFER_DATA(input), EVBUFFER_LENGTH(input));
200 
201 	while (conn->ber.br_rend - conn->ber.br_rptr > 0) {
202 		if (conn_dispatch(conn) == 0)
203 			nused = conn->ber.br_rptr - conn->ber.br_rbuf;
204 		else
205 			break;
206 	}
207 
208 	evbuffer_drain(input, nused);
209 }
210 
211 void
212 conn_write(struct bufferevent *bev, void *data)
213 {
214 	struct search	*search, *next;
215 	struct conn	*conn = data;
216 
217 	/* Continue any ongoing searches.
218 	 * Note that the search may be unlinked and freed by conn_search.
219 	 */
220 	for (search = TAILQ_FIRST(&conn->searches); search; search = next) {
221 		next = TAILQ_NEXT(search, next);
222 		conn_search(search);
223 	}
224 
225 	if (conn->disconnect)
226 		conn_close(conn);
227 	else if (conn->s_flags & F_STARTTLS) {
228 		conn->s_flags &= ~F_STARTTLS;
229 		if (conn_tls_init(conn) == -1)
230 			conn_close(conn);
231 	}
232 }
233 
234 void
235 conn_err(struct bufferevent *bev, short why, void *data)
236 {
237 	struct conn	*conn = data;
238 
239 	if ((why & EVBUFFER_EOF) == EVBUFFER_EOF)
240 		log_debug("end-of-file on connection %d", conn->fd);
241 	else if ((why & EVBUFFER_TIMEOUT) == EVBUFFER_TIMEOUT)
242 		log_debug("timeout on connection %d", conn->fd);
243 	else
244 		log_warnx("error 0x%02X on connection %d", why, conn->fd);
245 
246 	conn_close(conn);
247 }
248 
249 void
250 conn_accept(int fd, short event, void *data)
251 {
252 	int			 afd;
253 	socklen_t		 addrlen;
254 	struct conn		*conn;
255 	struct listener		*l = data;
256 	struct sockaddr_storage	 remote_addr;
257 	char			 host[128];
258 
259 	event_add(&l->ev, NULL);
260 	if ((event & EV_TIMEOUT))
261 		return;
262 
263 	addrlen = sizeof(remote_addr);
264 	afd = accept_reserve(fd, (struct sockaddr *)&remote_addr, &addrlen,
265 	    FD_RESERVE);
266 	if (afd == -1) {
267 		/*
268 		 * Pause accept if we are out of file descriptors, or
269 		 * libevent will haunt us here too.
270 		 */
271 		if (errno == ENFILE || errno == EMFILE) {
272 			struct timeval evtpause = { 1, 0 };
273 
274 			event_del(&l->ev);
275 			evtimer_add(&l->evt, &evtpause);
276 		} else if (errno != EWOULDBLOCK && errno != EINTR)
277 			log_warn("conn_accept");
278 		return;
279 	}
280 
281 	if (l->ss.ss_family == AF_UNIX) {
282 		uid_t		 euid;
283 		gid_t		 egid;
284 
285 		if (getpeereid(afd, &euid, &egid) == -1)
286 			log_warnx("conn_accept: getpeereid");
287 		else
288 			log_debug("accepted local connection by uid %d", euid);
289 	} else {
290 		print_host(&remote_addr, host, sizeof(host));
291 		log_debug("accepted connection from %s on fd %d", host, afd);
292 	}
293 
294 	if ((conn = calloc(1, sizeof(*conn))) == NULL) {
295 		log_warn("malloc");
296 		goto giveup;
297 	}
298 	conn->ber.fd = -1;
299 	ber_set_application(&conn->ber, ldap_application);
300 	conn->fd = afd;
301 	conn->listener = l;
302 
303 	conn->bev = bufferevent_new(afd, conn_read, conn_write,
304 	    conn_err, conn);
305 	if (conn->bev == NULL) {
306 		log_warn("conn_accept: bufferevent_new");
307 		free(conn);
308 		goto giveup;
309 	}
310 	bufferevent_enable(conn->bev, EV_READ);
311 	bufferevent_settimeout(conn->bev, 0, 60);
312 	if (l->flags & F_LDAPS)
313 		if (conn_tls_init(conn) == -1)
314 			conn_close(conn);
315 
316 	TAILQ_INIT(&conn->searches);
317 	TAILQ_INSERT_HEAD(&conn_list, conn, next);
318 
319 	if (l->flags & F_SECURE)
320 		conn->s_flags |= F_SECURE;
321 
322 	++stats.conns;
323 	return;
324 giveup:
325 	close(afd);
326 	/* Some file descriptors are available again. */
327 	if (evtimer_pending(&l->evt, NULL)) {
328 		evtimer_del(&l->evt);
329 		event_add(&l->ev, NULL);
330 	}
331 }
332 
333 struct conn *
334 conn_by_fd(int fd)
335 {
336 	struct conn		*conn;
337 
338 	TAILQ_FOREACH(conn, &conn_list, next) {
339 		if (conn->fd == fd)
340 			return conn;
341 	}
342 	return NULL;
343 }
344 
345 int
346 conn_close_any()
347 {
348 	struct conn		*conn;
349 
350 	/* Close oldest idle connection */
351 	TAILQ_FOREACH_REVERSE(conn, &conn_list, conn_list, next) {
352 		if (namespace_conn_queue_count(conn) == 0) {
353 			conn_close(conn);
354 			return 0;
355 		}
356 	}
357 
358 	/* Close oldest connection */
359 	conn = TAILQ_LAST(&conn_list, conn_list);
360 	if (conn != NULL) {
361 		conn_close(conn);
362 		return 0;
363 	}
364 
365 	return -1;
366 }
367 
368 int
369 conn_tls_init(struct conn *conn)
370 {
371 	struct listener *l = conn->listener;
372 
373 	if (!(l->flags & F_SSL))
374 		return 0;
375 
376 	log_debug("conn_tls_init: switching to TLS");
377 
378 	if (tls_accept_socket(l->tls, &conn->tls, conn->fd) < 0) {
379 		log_debug("tls_accept_socket failed");
380 		return -1;
381 	}
382 
383 	conn->s_flags |= F_SECURE;
384 	buffertls_set(&conn->buftls, conn->bev, conn->tls, conn->fd);
385 	buffertls_accept(&conn->buftls, conn->fd);
386 	return 0;
387 }
388