Annotation of embedaddon/mpd/src/contrib/libpdel/io/ssl_fp.c, revision 1.1.1.2.2.1
1.1 misho 1:
2: /*
3: * Copyright (c) 2001-2002 Packet Design, LLC.
4: * All rights reserved.
5: *
6: * Subject to the following obligations and disclaimer of warranty,
7: * use and redistribution of this software, in source or object code
8: * forms, with or without modifications are expressly permitted by
9: * Packet Design; provided, however, that:
10: *
11: * (i) Any and all reproductions of the source or object code
12: * must include the copyright notice above and the following
13: * disclaimer of warranties; and
14: * (ii) No rights are granted, in any manner or form, to use
15: * Packet Design trademarks, including the mark "PACKET DESIGN"
16: * on advertising, endorsements, or otherwise except as such
17: * appears in the above copyright notice or in the software.
18: *
19: * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
20: * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
21: * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
22: * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
23: * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
24: * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
25: * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
26: * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
27: * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE
28: * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
29: * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
30: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
31: * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
32: * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
33: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
35: * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
36: * THE POSSIBILITY OF SUCH DAMAGE.
37: *
38: * Author: Archie Cobbs <archie@freebsd.org>
39: */
40:
41: #include <sys/param.h>
42: #include <sys/syslog.h>
43:
44: #include <stdio.h>
45: #include <stdlib.h>
46: #include <stdarg.h>
47: #include <string.h>
48: #include <unistd.h>
49: #include <fcntl.h>
50: #include <errno.h>
51: #include <poll.h>
52: #include <pthread.h>
53:
54: #include <openssl/ssl.h>
55: #include <openssl/err.h>
1.1.1.2.2.1! misho 56: #include <openssl/opensslv.h>
1.1 misho 57:
58: #include "structs/structs.h"
59: #include "structs/type/array.h"
60:
61: #include "util/typed_mem.h"
62: #include "io/ssl_fp.h"
63:
64: struct ssl_info {
65: int fd;
66: SSL *ssl;
67: SSL_CTX *ssl_ctx;
68: int error;
69: u_char server;
70: ssl_logger_t *logger;
71: void *logarg;
72: const char *mtype;
73: u_int timeout;
74: };
75:
76: /*
77: * Internal functions
78: */
79: static int ssl_read(void *cookie, char *buf, int len);
80: static int ssl_write(void *cookie, const char *buf, int len);
81: static int ssl_close(void *cookie);
82: static int ssl_check(struct ssl_info *s);
83: static int ssl_err(struct ssl_info *s, int ret);
84:
85: static ssl_logger_t null_logger;
86:
87: /*
88: * Create a FILE * from an SSL connection.
89: */
90: FILE *
91: ssl_fdopen(SSL_CTX *ssl_ctx, int fd, int server, const char *mtype,
92: ssl_logger_t *logger, void *logarg, u_int timeout)
93: {
94: struct ssl_info *s;
95: int flags;
96: FILE *fp;
97:
98: /* Create SSL info */
99: if ((s = MALLOC(mtype, sizeof(*s))) == NULL)
100: return (NULL);
101: memset(s, 0, sizeof(*s));
102: s->fd = fd;
103: s->ssl_ctx = ssl_ctx;
104: s->mtype = mtype;
105: s->server = !!server;
106: s->logger = (logger != NULL) ? logger : null_logger;
107: s->logarg = logarg;
108: s->timeout = timeout;
109:
110: /* Set fd I/O to non-blocking */
111: if ((flags = fcntl(fd, F_GETFL, 0)) == -1) {
112: FREE(mtype, s);
113: return (NULL);
114: }
115: #if 0
116: if ((flags & O_NONBLOCK) == 0
117: && fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
118: FREE(mtype, s);
119: return (NULL);
120: }
121: #endif
122:
123: /* Create FILE * stream */
124: if ((fp = funopen(s, ssl_read, ssl_write, NULL, ssl_close)) == NULL) {
125: (void)fcntl(fd, F_SETFL, flags);
126: FREE(mtype, s);
127: return (NULL);
128: }
129:
130: /* Done */
131: return (fp);
132: }
133:
134: /*
135: * Read from an SSL connection.
136: */
137: static int
138: ssl_read(void *cookie, char *buf, int len)
139: {
140: struct ssl_info *const s = cookie;
141: int ret;
142:
143: /* Check connection */
144: if (ssl_check(s) == -1)
145: return (-1);
146:
147: tryread:
148: /* Try to read some more data */
149: if ((ret = SSL_read(s->ssl, buf, len)) <= 0) {
150: if (ssl_err(s, ret) == -1)
151: return (-1);
152: goto tryread;
153: }
154: return (ret);
155: }
156:
157: /*
158: * Write to an SSL connection.
159: */
160: static int
161: ssl_write(void *cookie, const char *buf, int len)
162: {
163: struct ssl_info *const s = cookie;
164: int ret;
165:
166: /* Check connection */
167: if (ssl_check(s) == -1)
168: return (-1);
169:
170: trywrite:
171: /* Try to write some more data */
172: if ((ret = SSL_write(s->ssl, buf, len)) <= 0) {
173: if (ssl_err(s, ret) == -1)
174: return (-1);
175: goto trywrite;
176: }
177: return (ret);
178: }
179:
180: /*
181: * Close an SSL connection.
182: */
183: static int
184: ssl_close(void *cookie)
185: {
186: struct ssl_info *const s = cookie;
187: int ret;
188:
189: while ((ret = SSL_shutdown(s->ssl)) <= 0) {
190: if (ret == -1 && ssl_err(s, ret) == -1) {
191: (void)close(s->fd);
192: return (-1);
193: }
194: }
195: (void)close(s->fd);
196: SSL_free(s->ssl);
197: FREE(s->mtype, s);
198: return (0);
199: }
200:
201: /*
202: * Check SSL connection context.
203: */
204: static int
205: ssl_check(struct ssl_info *s)
206: {
207: int ret;
208:
209: /* Check for previous error */
210: if (s->error != 0)
211: goto fail;
212:
213: /* Already set up SSL? */
214: if (s->ssl != NULL)
215: return (0);
216:
217: /* Create ssl connection context */
218: if ((s->ssl = SSL_new(s->ssl_ctx)) == NULL) {
219: ssl_log(s->logger, s->logarg);
220: s->error = ECONNABORTED;
221: goto fail;
222: }
223: SSL_set_fd(s->ssl, s->fd);
224:
225: /* Do initial SSL handshake */
226: if (s->server) {
227: while ((ret = SSL_accept(s->ssl)) <= 0) {
228: if (ssl_err(s, ret) == -1)
229: goto fail;
230: }
231: } else {
232: while ((ret = SSL_connect(s->ssl)) <= 0) {
233: if (ssl_err(s, ret) == -1)
234: goto fail;
235: }
236: }
237:
238: /* Ready */
239: return (0);
240:
241: fail:
242: /* Failed */
243: errno = s->error;
244: return (-1);
245: }
246:
247: /*
248: * Handle an error return from an SSL I/O operation.
249: *
250: * It might be an error, or it might just be that more raw data
251: * needs to be read or written. Return -1 in the former case,
252: * otherwise return zero and wait for the readable or writable
253: * event as appropriate.
254: */
255: static int
256: ssl_err(struct ssl_info *s, int ret)
257: {
258: int ret2;
259:
260: ret2 = SSL_get_error(s->ssl, ret);
261: switch (ret2) {
262: case SSL_ERROR_WANT_READ:
263: case SSL_ERROR_WANT_WRITE:
264: {
265: struct pollfd pfd;
266: int timeout;
267: int nfds;
268:
269: /* Set up read/write poll(2) event */
270: memset(&pfd, 0, sizeof(pfd));
271: pfd.fd = s->fd;
272: pfd.events = (ret2 == SSL_ERROR_WANT_READ) ?
273: POLLRDNORM : POLLWRNORM;
274:
275: /* Set up timeout */
276: timeout = INFTIM;
277: if (s->timeout != 0)
278: timeout = s->timeout * 1000;
279:
280: /* Wait for readability or writability */
281: if ((nfds = poll(&pfd, 1, timeout)) == -1) {
282: s->error = errno;
283: (*s->logger)(s->logarg, LOG_ERR,
284: "%s: %s", "poll", strerror(errno));
285: goto fail;
286: }
287:
288: /* Check for timeout */
289: if (nfds == 0) {
290: s->error = ETIMEDOUT;
291: goto fail;
292: }
293:
294: /* Done */
295: return (0);
296: }
297: case SSL_ERROR_NONE:
298: return (0);
299:
300: case SSL_ERROR_SYSCALL:
301: ssl_log(s->logger, s->logarg);
302: if (ret != 0) {
303: s->error = errno;
304: (*s->logger)(s->logarg, LOG_ERR,
305: "SSL system error: %s", strerror(errno));
306: goto fail;
307: }
308: /* fall through */
309:
310: case SSL_ERROR_ZERO_RETURN:
311: (*s->logger)(s->logarg, LOG_ERR, "SSL connection closed");
312: s->error = ECONNRESET;
313: goto fail;
314:
315: case SSL_ERROR_SSL:
316: ssl_log(s->logger, s->logarg);
317: s->error = EIO;
318: goto fail;
319:
320: case SSL_ERROR_WANT_X509_LOOKUP: /* should not happen */
321: default:
322: ssl_log(s->logger, s->logarg);
323: (*s->logger)(s->logarg, LOG_ERR,
324: "unknown return %d from SSL_get_error", ret2);
325: s->error = ECONNABORTED;
326: goto fail;
327: }
328:
329: fail:
330: /* Got an error */
331: errno = s->error;
332: return (-1);
333: }
334:
335: /*
336: * Log an SSL error.
337: */
338: void
339: ssl_log(ssl_logger_t *logger, void *logarg)
340: {
341: char buf[200];
342: const char *file;
343: const char *str;
344: const char *t;
345: int line, flags;
346: u_long e;
347:
348: while ((e = ERR_get_error_line_data(&file, &line, &str, &flags)) != 0) {
349: if (logger == NULL)
350: continue;
351: #if 0
352: (*logger)(logarg, LOG_ERR, "SSL: %s:%s:%d:%s\n",
353: ERR_error_string(e, buf), file, line,
354: (flags & ERR_TXT_STRING) ? str : "");
355: #else
356: strlcpy(buf, "SSL: ", sizeof(buf));
357: #if 0
358: /* Add library */
359: if ((t = ERR_lib_error_string(e)) != NULL) {
360: strlcat(buf, t, sizeof(buf));
361: strlcat(buf, ": ", sizeof(buf));
362: } else {
363: snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
364: "lib=%u: ", ERR_GET_LIB(e));
365: }
366: #endif
367:
1.1.1.2.2.1! misho 368: #if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x30000000L
1.1 misho 369: /* Add function */
370: if ((t = ERR_func_error_string(e)) != NULL) {
371: strlcat(buf, t, sizeof(buf));
372: strlcat(buf, ": ", sizeof(buf));
373: } else {
374: snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
375: "func=%u: ", ERR_GET_FUNC(e));
376: }
1.1.1.2.2.1! misho 377: #endif
1.1 misho 378:
379: /* Add reason */
380: if ((t = ERR_reason_error_string(e)) != NULL) {
381: strlcat(buf, t, sizeof(buf));
382: } else {
383: snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
384: "reason=%u", ERR_GET_REASON(e));
385: }
386:
387: /* Add error text, if any */
388: if ((flags & ERR_TXT_STRING) != 0) {
389: strlcat(buf, ": ", sizeof(buf));
390: strlcat(buf, str, sizeof(buf));
391: }
392: (*logger)(logarg, LOG_ERR, "%s", buf);
393: #endif
394: }
395: }
396:
397: static void
398: null_logger(void *arg, int sev, const char *fmt, ...)
399: {
1.1.1.2 misho 400: (void)arg;
401: (void)sev;
402: (void)fmt;
403:
1.1 misho 404: return;
405: }
406:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>