xref: /openbsd-src/usr.sbin/syslogd/evbuffer_tls.c (revision d4d4d7d2061a965aa1c361ff8e6a46f7690e3433)
1 /*	$OpenBSD: evbuffer_tls.c,v 1.4 2015/07/06 16:12:16 millert 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 int evtls_read(struct evbuffer *, int, int, struct tls *);
48 int evtls_write(struct evbuffer *, int, struct tls *);
49 
50 static int
51 bufferevent_add(struct event *ev, int timeout)
52 {
53 	struct timeval tv, *ptv = NULL;
54 
55 	if (timeout) {
56 		timerclear(&tv);
57 		tv.tv_sec = timeout;
58 		ptv = &tv;
59 	}
60 
61 	return (event_add(ev, ptv));
62 }
63 
64 static void
65 buffertls_readcb(int fd, short event, void *arg)
66 {
67 	struct buffertls *buftls = arg;
68 	struct bufferevent *bufev = buftls->bt_bufev;
69 	struct tls *ctx = buftls->bt_ctx;
70 	int res = 0;
71 	short what = EVBUFFER_READ;
72 	size_t len;
73 	int howmuch = -1;
74 
75 	if (event == EV_TIMEOUT) {
76 		what |= EVBUFFER_TIMEOUT;
77 		goto error;
78 	}
79 
80 	/*
81 	 * If we have a high watermark configured then we don't want to
82 	 * read more data than would make us reach the watermark.
83 	 */
84 	if (bufev->wm_read.high != 0) {
85 		howmuch = bufev->wm_read.high - EVBUFFER_LENGTH(bufev->input);
86 		/* we might have lowered the watermark, stop reading */
87 		if (howmuch <= 0) {
88 			struct evbuffer *buf = bufev->input;
89 			event_del(&bufev->ev_read);
90 			evbuffer_setcb(buf,
91 			    bufferevent_read_pressure_cb, bufev);
92 			return;
93 		}
94 	}
95 
96 	res = evtls_read(bufev->input, fd, howmuch, ctx);
97 	switch (res) {
98 	case TLS_READ_AGAIN:
99 		event_set(&bufev->ev_read, fd, EV_READ, buffertls_readcb,
100 		    buftls);
101 		goto reschedule;
102 	case TLS_WRITE_AGAIN:
103 		event_set(&bufev->ev_read, fd, EV_WRITE, buffertls_readcb,
104 		    buftls);
105 		goto reschedule;
106 	case -1:
107 		if (errno == EAGAIN || errno == EINTR)
108 			goto reschedule;
109 		/* error case */
110 		what |= EVBUFFER_ERROR;
111 		break;
112 	case 0:
113 		/* eof case */
114 		what |= EVBUFFER_EOF;
115 		break;
116 	}
117 	if (res <= 0)
118 		goto error;
119 
120 	event_set(&bufev->ev_read, fd, EV_READ, buffertls_readcb, buftls);
121 	bufferevent_add(&bufev->ev_read, bufev->timeout_read);
122 
123 	/* See if this callbacks meets the water marks */
124 	len = EVBUFFER_LENGTH(bufev->input);
125 	if (bufev->wm_read.low != 0 && len < bufev->wm_read.low)
126 		return;
127 	if (bufev->wm_read.high != 0 && len >= bufev->wm_read.high) {
128 		struct evbuffer *buf = bufev->input;
129 		event_del(&bufev->ev_read);
130 
131 		/* Now schedule a callback for us when the buffer changes */
132 		evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev);
133 	}
134 
135 	/* Invoke the user callback - must always be called last */
136 	if (bufev->readcb != NULL)
137 		(*bufev->readcb)(bufev, bufev->cbarg);
138 	return;
139 
140  reschedule:
141 	bufferevent_add(&bufev->ev_read, bufev->timeout_read);
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_READ_AGAIN:
166 			event_set(&bufev->ev_write, fd, EV_READ,
167 			    buffertls_writecb, buftls);
168 			goto reschedule;
169 		case TLS_WRITE_AGAIN:
170 			event_set(&bufev->ev_write, fd, EV_WRITE,
171 			    buffertls_writecb, buftls);
172 			goto reschedule;
173 		case -1:
174 			if (errno == EAGAIN || errno == EINTR ||
175 			    errno == EINPROGRESS)
176 				goto reschedule;
177 			/* error case */
178 			what |= EVBUFFER_ERROR;
179 			break;
180 		case 0:
181 			/* eof case */
182 			what |= EVBUFFER_EOF;
183 			break;
184 		}
185 		if (res <= 0)
186 			goto error;
187 	}
188 	buftls->bt_flags &= ~BT_WRITE_AGAIN;
189 
190 	event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_writecb, buftls);
191 	if (EVBUFFER_LENGTH(bufev->output) != 0)
192 		bufferevent_add(&bufev->ev_write, bufev->timeout_write);
193 
194 	/*
195 	 * Invoke the user callback if our buffer is drained or below the
196 	 * low watermark.
197 	 */
198 	if (bufev->writecb != NULL &&
199 	    EVBUFFER_LENGTH(bufev->output) <= bufev->wm_write.low)
200 		(*bufev->writecb)(bufev, bufev->cbarg);
201 
202 	return;
203 
204  reschedule:
205 	buftls->bt_flags |= BT_WRITE_AGAIN;
206 	if (EVBUFFER_LENGTH(bufev->output) != 0)
207 		bufferevent_add(&bufev->ev_write, bufev->timeout_write);
208 	return;
209 
210  error:
211 	(*bufev->errorcb)(bufev, what, bufev->cbarg);
212 }
213 
214 static void
215 buffertls_connectcb(int fd, short event, void *arg)
216 {
217 	struct buffertls *buftls = arg;
218 	struct bufferevent *bufev = buftls->bt_bufev;
219 	struct tls *ctx = buftls->bt_ctx;
220 	const char *hostname = buftls->bt_hostname;
221 	int res = 0;
222 	short what = EVBUFFER_CONNECT;
223 
224 	if (event == EV_TIMEOUT) {
225 		what |= EVBUFFER_TIMEOUT;
226 		goto error;
227 	}
228 
229 	res = tls_connect_socket(ctx, fd, hostname);
230 	switch (res) {
231 	case TLS_READ_AGAIN:
232 		event_set(&bufev->ev_write, fd, EV_READ,
233 		    buffertls_connectcb, buftls);
234 		goto reschedule;
235 	case TLS_WRITE_AGAIN:
236 		event_set(&bufev->ev_write, fd, EV_WRITE,
237 		    buffertls_connectcb, buftls);
238 		goto reschedule;
239 	case -1:
240 		if (errno == EAGAIN || errno == EINTR ||
241 		    errno == EINPROGRESS)
242 			goto reschedule;
243 		/* error case */
244 		what |= EVBUFFER_ERROR;
245 		break;
246 	}
247 	if (res < 0)
248 		goto error;
249 
250 	/*
251 	 * There might be data available in the tls layer.  Try
252 	 * an read operation and setup the callbacks.  Call the read
253 	 * callback after enabling the write callback to give the
254 	 * read error handler a chance to disable the write event.
255 	 */
256 	event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_writecb, buftls);
257 	if (EVBUFFER_LENGTH(bufev->output) != 0)
258 		bufferevent_add(&bufev->ev_write, bufev->timeout_write);
259 	buffertls_readcb(fd, 0, buftls);
260 
261 	return;
262 
263  reschedule:
264 	bufferevent_add(&bufev->ev_write, bufev->timeout_write);
265 	return;
266 
267  error:
268 	(*bufev->errorcb)(bufev, what, bufev->cbarg);
269 }
270 
271 void
272 buffertls_set(struct buffertls *buftls, struct bufferevent *bufev,
273     struct tls *ctx, int fd)
274 {
275 	bufferevent_setfd(bufev, fd);
276 	event_set(&bufev->ev_read, fd, EV_READ, buffertls_readcb, buftls);
277 	event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_writecb, buftls);
278 	buftls->bt_bufev = bufev;
279 	buftls->bt_ctx = ctx;
280 	buftls->bt_flags = 0;
281 }
282 
283 void
284 buffertls_connect(struct buffertls *buftls, int fd, const char *hostname)
285 {
286 	struct bufferevent *bufev = buftls->bt_bufev;
287 
288 	event_del(&bufev->ev_read);
289 	event_del(&bufev->ev_write);
290 
291 	buftls->bt_hostname = hostname;
292 	event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_connectcb, buftls);
293 	bufferevent_add(&bufev->ev_write, bufev->timeout_write);
294 }
295 
296 /*
297  * Reads data from a file descriptor into a buffer.
298  */
299 
300 #define EVBUFFER_MAX_READ	4096
301 
302 int
303 evtls_read(struct evbuffer *buf, int fd, int howmuch, struct tls *ctx)
304 {
305 	u_char *p;
306 	size_t len, oldoff = buf->off;
307 	int n = EVBUFFER_MAX_READ;
308 
309 	if (ioctl(fd, FIONREAD, &n) == -1 || n <= 0) {
310 		n = EVBUFFER_MAX_READ;
311 	} else if (n > EVBUFFER_MAX_READ && n > howmuch) {
312 		/*
313 		 * It's possible that a lot of data is available for
314 		 * reading.  We do not want to exhaust resources
315 		 * before the reader has a chance to do something
316 		 * about it.  If the reader does not tell us how much
317 		 * data we should read, we artifically limit it.
318 		 */
319 		if ((size_t)n > buf->totallen << 2)
320 			n = buf->totallen << 2;
321 		if (n < EVBUFFER_MAX_READ)
322 			n = EVBUFFER_MAX_READ;
323 	}
324 	if (howmuch < 0 || howmuch > n)
325 		howmuch = n;
326 
327 	/* If we don't have FIONREAD, we might waste some space here */
328 	if (evbuffer_expand(buf, howmuch) == -1)
329 		return (-1);
330 
331 	/* We can append new data at this point */
332 	p = buf->buffer + buf->off;
333 
334 	n = tls_read(ctx, p, howmuch, &len);
335 	if (n < 0 || len == 0)
336 		return (n);
337 
338 	buf->off += len;
339 
340 	/* Tell someone about changes in this buffer */
341 	if (buf->off != oldoff && buf->cb != NULL)
342 		(*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
343 
344 	return (len);
345 }
346 
347 int
348 evtls_write(struct evbuffer *buffer, int fd, struct tls *ctx)
349 {
350 	size_t len;
351 	int n;
352 
353 	n = tls_write(ctx, buffer->buffer, buffer->off, &len);
354 	if (n < 0 || len == 0)
355 		return (n);
356 
357 	evbuffer_drain(buffer, len);
358 
359 	return (len);
360 }
361