xref: /openbsd-src/usr.sbin/syslogd/evbuffer_tls.c (revision 1cfd376a1dba5eeb3201d3836982234b3b55bbe4)
1 /*	$OpenBSD: evbuffer_tls.c,v 1.9 2015/10/09 16:58:25 bluhm Exp $ */
2 
3 /*
4  * Copyright (c) 2002-2004 Niels Provos <provos@citi.umich.edu>
5  * Copyright (c) 2014-2015 Alexander Bluhm <bluhm@openbsd.org>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include <sys/types.h>
32 #include <sys/time.h>
33 #include <sys/ioctl.h>
34 
35 #include <errno.h>
36 #include <event.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <tls.h>
41 
42 #include "evbuffer_tls.h"
43 
44 /* prototypes */
45 
46 void bufferevent_read_pressure_cb(struct evbuffer *, size_t, size_t, void *);
47 static void buffertls_readcb(int, short, void *);
48 static void buffertls_writecb(int, short, void *);
49 static void buffertls_handshakecb(int, short, void *);
50 int evtls_read(struct evbuffer *, int, int, struct tls *);
51 int evtls_write(struct evbuffer *, int, struct tls *);
52 
53 static int
54 bufferevent_add(struct event *ev, int timeout)
55 {
56 	struct timeval tv, *ptv = NULL;
57 
58 	if (timeout) {
59 		timerclear(&tv);
60 		tv.tv_sec = timeout;
61 		ptv = &tv;
62 	}
63 
64 	return (event_add(ev, ptv));
65 }
66 
67 static void
68 buffertls_readcb(int fd, short event, void *arg)
69 {
70 	struct buffertls *buftls = arg;
71 	struct bufferevent *bufev = buftls->bt_bufev;
72 	struct tls *ctx = buftls->bt_ctx;
73 	int res = 0;
74 	short what = EVBUFFER_READ;
75 	size_t len;
76 	int howmuch = -1;
77 
78 	if (event == EV_TIMEOUT) {
79 		what |= EVBUFFER_TIMEOUT;
80 		goto error;
81 	}
82 
83 	/*
84 	 * If we have a high watermark configured then we don't want to
85 	 * read more data than would make us reach the watermark.
86 	 */
87 	if (bufev->wm_read.high != 0) {
88 		howmuch = bufev->wm_read.high - EVBUFFER_LENGTH(bufev->input);
89 		/* we might have lowered the watermark, stop reading */
90 		if (howmuch <= 0) {
91 			struct evbuffer *buf = bufev->input;
92 			event_del(&bufev->ev_read);
93 			evbuffer_setcb(buf,
94 			    bufferevent_read_pressure_cb, bufev);
95 			return;
96 		}
97 	}
98 
99 	res = evtls_read(bufev->input, fd, howmuch, ctx);
100 	switch (res) {
101 	case TLS_WANT_POLLIN:
102 		bufferevent_add(&bufev->ev_read, bufev->timeout_read);
103 		return;
104 	case TLS_WANT_POLLOUT:
105 		event_del(&bufev->ev_write);
106 		event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_readcb,
107 		    buftls);
108 		bufferevent_add(&bufev->ev_write, bufev->timeout_write);
109 		return;
110 	case -1:
111 		what |= EVBUFFER_ERROR;
112 		break;
113 	case 0:
114 		what |= EVBUFFER_EOF;
115 		break;
116 	}
117 	if (res <= 0)
118 		goto error;
119 
120 	event_del(&bufev->ev_write);
121 	event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_writecb, buftls);
122 	if (bufev->enabled & EV_READ)
123 		bufferevent_add(&bufev->ev_read, bufev->timeout_read);
124 	if (EVBUFFER_LENGTH(bufev->output) != 0 && bufev->enabled & EV_WRITE)
125 		bufferevent_add(&bufev->ev_write, bufev->timeout_write);
126 
127 	/* See if this callbacks meets the water marks */
128 	len = EVBUFFER_LENGTH(bufev->input);
129 	if (bufev->wm_read.low != 0 && len < bufev->wm_read.low)
130 		return;
131 	if (bufev->wm_read.high != 0 && len >= bufev->wm_read.high) {
132 		struct evbuffer *buf = bufev->input;
133 		event_del(&bufev->ev_read);
134 
135 		/* Now schedule a callback for us when the buffer changes */
136 		evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev);
137 	}
138 
139 	/* Invoke the user callback - must always be called last */
140 	if (bufev->readcb != NULL)
141 		(*bufev->readcb)(bufev, bufev->cbarg);
142 	return;
143 
144  error:
145 	(*bufev->errorcb)(bufev, what, bufev->cbarg);
146 }
147 
148 static void
149 buffertls_writecb(int fd, short event, void *arg)
150 {
151 	struct buffertls *buftls = arg;
152 	struct bufferevent *bufev = buftls->bt_bufev;
153 	struct tls *ctx = buftls->bt_ctx;
154 	int res = 0;
155 	short what = EVBUFFER_WRITE;
156 
157 	if (event == EV_TIMEOUT) {
158 		what |= EVBUFFER_TIMEOUT;
159 		goto error;
160 	}
161 
162 	if (EVBUFFER_LENGTH(bufev->output) != 0) {
163 		res = evtls_write(bufev->output, fd, ctx);
164 		switch (res) {
165 		case TLS_WANT_POLLIN:
166 			event_del(&bufev->ev_read);
167 			event_set(&bufev->ev_read, fd, EV_READ,
168 			    buffertls_writecb, buftls);
169 			bufferevent_add(&bufev->ev_read, bufev->timeout_read);
170 			return;
171 		case TLS_WANT_POLLOUT:
172 			bufferevent_add(&bufev->ev_write, bufev->timeout_write);
173 			return;
174 		case -1:
175 			what |= EVBUFFER_ERROR;
176 			break;
177 		case 0:
178 			what |= EVBUFFER_EOF;
179 			break;
180 		}
181 		if (res <= 0)
182 			goto error;
183 	}
184 
185 	event_del(&bufev->ev_read);
186 	event_set(&bufev->ev_read, fd, EV_READ, buffertls_readcb, buftls);
187 	if (bufev->enabled & EV_READ)
188 		bufferevent_add(&bufev->ev_read, bufev->timeout_read);
189 	if (EVBUFFER_LENGTH(bufev->output) != 0 && bufev->enabled & EV_WRITE)
190 		bufferevent_add(&bufev->ev_write, bufev->timeout_write);
191 
192 	/*
193 	 * Invoke the user callback if our buffer is drained or below the
194 	 * low watermark.
195 	 */
196 	if (bufev->writecb != NULL &&
197 	    EVBUFFER_LENGTH(bufev->output) <= bufev->wm_write.low)
198 		(*bufev->writecb)(bufev, bufev->cbarg);
199 
200 	return;
201 
202  error:
203 	(*bufev->errorcb)(bufev, what, bufev->cbarg);
204 }
205 
206 static void
207 buffertls_handshakecb(int fd, short event, void *arg)
208 {
209 	struct buffertls *buftls = arg;
210 	struct bufferevent *bufev = buftls->bt_bufev;
211 	struct tls *ctx = buftls->bt_ctx;
212 	int res = 0;
213 	short what = EVBUFFER_HANDSHAKE;
214 
215 	if (event == EV_TIMEOUT) {
216 		what |= EVBUFFER_TIMEOUT;
217 		goto error;
218 	}
219 
220 	res = tls_handshake(ctx);
221 	switch (res) {
222 	case TLS_WANT_POLLIN:
223 		bufferevent_add(&bufev->ev_read, bufev->timeout_read);
224 		return;
225 	case TLS_WANT_POLLOUT:
226 		bufferevent_add(&bufev->ev_write, bufev->timeout_write);
227 		return;
228 	case -1:
229 		what |= EVBUFFER_ERROR;
230 		break;
231 	}
232 	if (res < 0)
233 		goto error;
234 
235 	/* Handshake was successful, change to read and write callback. */
236 	event_del(&bufev->ev_read);
237 	event_del(&bufev->ev_write);
238 	event_set(&bufev->ev_read, fd, EV_READ, buffertls_readcb, buftls);
239 	event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_writecb, buftls);
240 	if (bufev->enabled & EV_READ)
241 		bufferevent_add(&bufev->ev_read, bufev->timeout_read);
242 	if (EVBUFFER_LENGTH(bufev->output) != 0 && bufev->enabled & EV_WRITE)
243 		bufferevent_add(&bufev->ev_write, bufev->timeout_write);
244 
245 	return;
246 
247  error:
248 	(*bufev->errorcb)(bufev, what, bufev->cbarg);
249 }
250 
251 void
252 buffertls_set(struct buffertls *buftls, struct bufferevent *bufev,
253     struct tls *ctx, int fd)
254 {
255 	bufferevent_setfd(bufev, fd);
256 	event_set(&bufev->ev_read, fd, EV_READ, buffertls_readcb, buftls);
257 	event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_writecb, buftls);
258 	buftls->bt_bufev = bufev;
259 	buftls->bt_ctx = ctx;
260 }
261 
262 void
263 buffertls_accept(struct buffertls *buftls, int fd)
264 {
265 	struct bufferevent *bufev = buftls->bt_bufev;
266 
267 	event_del(&bufev->ev_read);
268 	event_del(&bufev->ev_write);
269 	event_set(&bufev->ev_read, fd, EV_READ, buffertls_handshakecb, buftls);
270 	event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_handshakecb,
271 	    buftls);
272 	bufferevent_add(&bufev->ev_read, bufev->timeout_read);
273 }
274 
275 void
276 buffertls_connect(struct buffertls *buftls, int fd)
277 {
278 	struct bufferevent *bufev = buftls->bt_bufev;
279 
280 	event_del(&bufev->ev_read);
281 	event_del(&bufev->ev_write);
282 	event_set(&bufev->ev_read, fd, EV_READ, buffertls_handshakecb, buftls);
283 	event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_handshakecb,
284 	    buftls);
285 	bufferevent_add(&bufev->ev_write, bufev->timeout_write);
286 }
287 
288 /*
289  * Reads data from a file descriptor into a buffer.
290  */
291 
292 #define EVBUFFER_MAX_READ	4096
293 
294 int
295 evtls_read(struct evbuffer *buf, int fd, int howmuch, struct tls *ctx)
296 {
297 	u_char *p;
298 	size_t oldoff = buf->off;
299 	int n = EVBUFFER_MAX_READ;
300 
301 	if (ioctl(fd, FIONREAD, &n) == -1 || n <= 0) {
302 		n = EVBUFFER_MAX_READ;
303 	} else if (n > EVBUFFER_MAX_READ && n > howmuch) {
304 		/*
305 		 * It's possible that a lot of data is available for
306 		 * reading.  We do not want to exhaust resources
307 		 * before the reader has a chance to do something
308 		 * about it.  If the reader does not tell us how much
309 		 * data we should read, we artifically limit it.
310 		 */
311 		if ((size_t)n > buf->totallen << 2)
312 			n = buf->totallen << 2;
313 		if (n < EVBUFFER_MAX_READ)
314 			n = EVBUFFER_MAX_READ;
315 	}
316 	if (howmuch < 0 || howmuch > n)
317 		howmuch = n;
318 
319 	/* If we don't have FIONREAD, we might waste some space here */
320 	if (evbuffer_expand(buf, howmuch) == -1)
321 		return (-1);
322 
323 	/* We can append new data at this point */
324 	p = buf->buffer + buf->off;
325 
326 	n = tls_read(ctx, p, howmuch);
327 	if (n <= 0)
328 		return (n);
329 
330 	buf->off += n;
331 
332 	/* Tell someone about changes in this buffer */
333 	if (buf->off != oldoff && buf->cb != NULL)
334 		(*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
335 
336 	return (n);
337 }
338 
339 int
340 evtls_write(struct evbuffer *buffer, int fd, struct tls *ctx)
341 {
342 	int n;
343 
344 	n = tls_write(ctx, buffer->buffer, buffer->off);
345 	if (n <= 0)
346 		return (n);
347 	evbuffer_drain(buffer, n);
348 
349 	return (n);
350 }
351