GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/ldapd/conn.c Lines: 0 169 0.0 %
Date: 2017-11-07 Branches: 0 86 0.0 %

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