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>