Return to ssl_fp.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / mpd / src / contrib / libpdel / io |
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> 56: 57: #include "structs/structs.h" 58: #include "structs/type/array.h" 59: 60: #include "util/typed_mem.h" 61: #include "io/ssl_fp.h" 62: 63: struct ssl_info { 64: int fd; 65: SSL *ssl; 66: SSL_CTX *ssl_ctx; 67: int error; 68: u_char server; 69: ssl_logger_t *logger; 70: void *logarg; 71: const char *mtype; 72: u_int timeout; 73: }; 74: 75: /* 76: * Internal functions 77: */ 78: static int ssl_read(void *cookie, char *buf, int len); 79: static int ssl_write(void *cookie, const char *buf, int len); 80: static int ssl_close(void *cookie); 81: static int ssl_check(struct ssl_info *s); 82: static int ssl_err(struct ssl_info *s, int ret); 83: 84: static ssl_logger_t null_logger; 85: 86: /* 87: * Create a FILE * from an SSL connection. 88: */ 89: FILE * 90: ssl_fdopen(SSL_CTX *ssl_ctx, int fd, int server, const char *mtype, 91: ssl_logger_t *logger, void *logarg, u_int timeout) 92: { 93: struct ssl_info *s; 94: int flags; 95: FILE *fp; 96: 97: /* Create SSL info */ 98: if ((s = MALLOC(mtype, sizeof(*s))) == NULL) 99: return (NULL); 100: memset(s, 0, sizeof(*s)); 101: s->fd = fd; 102: s->ssl_ctx = ssl_ctx; 103: s->mtype = mtype; 104: s->server = !!server; 105: s->logger = (logger != NULL) ? logger : null_logger; 106: s->logarg = logarg; 107: s->timeout = timeout; 108: 109: /* Set fd I/O to non-blocking */ 110: if ((flags = fcntl(fd, F_GETFL, 0)) == -1) { 111: FREE(mtype, s); 112: return (NULL); 113: } 114: #if 0 115: if ((flags & O_NONBLOCK) == 0 116: && fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) { 117: FREE(mtype, s); 118: return (NULL); 119: } 120: #endif 121: 122: /* Create FILE * stream */ 123: if ((fp = funopen(s, ssl_read, ssl_write, NULL, ssl_close)) == NULL) { 124: (void)fcntl(fd, F_SETFL, flags); 125: FREE(mtype, s); 126: return (NULL); 127: } 128: 129: /* Done */ 130: return (fp); 131: } 132: 133: /* 134: * Read from an SSL connection. 135: */ 136: static int 137: ssl_read(void *cookie, char *buf, int len) 138: { 139: struct ssl_info *const s = cookie; 140: int ret; 141: 142: /* Check connection */ 143: if (ssl_check(s) == -1) 144: return (-1); 145: 146: tryread: 147: /* Try to read some more data */ 148: if ((ret = SSL_read(s->ssl, buf, len)) <= 0) { 149: if (ssl_err(s, ret) == -1) 150: return (-1); 151: goto tryread; 152: } 153: return (ret); 154: } 155: 156: /* 157: * Write to an SSL connection. 158: */ 159: static int 160: ssl_write(void *cookie, const char *buf, int len) 161: { 162: struct ssl_info *const s = cookie; 163: int ret; 164: 165: /* Check connection */ 166: if (ssl_check(s) == -1) 167: return (-1); 168: 169: trywrite: 170: /* Try to write some more data */ 171: if ((ret = SSL_write(s->ssl, buf, len)) <= 0) { 172: if (ssl_err(s, ret) == -1) 173: return (-1); 174: goto trywrite; 175: } 176: return (ret); 177: } 178: 179: /* 180: * Close an SSL connection. 181: */ 182: static int 183: ssl_close(void *cookie) 184: { 185: struct ssl_info *const s = cookie; 186: int ret; 187: 188: while ((ret = SSL_shutdown(s->ssl)) <= 0) { 189: if (ret == -1 && ssl_err(s, ret) == -1) { 190: (void)close(s->fd); 191: return (-1); 192: } 193: } 194: (void)close(s->fd); 195: SSL_free(s->ssl); 196: FREE(s->mtype, s); 197: return (0); 198: } 199: 200: /* 201: * Check SSL connection context. 202: */ 203: static int 204: ssl_check(struct ssl_info *s) 205: { 206: int ret; 207: 208: /* Check for previous error */ 209: if (s->error != 0) 210: goto fail; 211: 212: /* Already set up SSL? */ 213: if (s->ssl != NULL) 214: return (0); 215: 216: /* Create ssl connection context */ 217: if ((s->ssl = SSL_new(s->ssl_ctx)) == NULL) { 218: ssl_log(s->logger, s->logarg); 219: s->error = ECONNABORTED; 220: goto fail; 221: } 222: SSL_set_fd(s->ssl, s->fd); 223: 224: /* Do initial SSL handshake */ 225: if (s->server) { 226: while ((ret = SSL_accept(s->ssl)) <= 0) { 227: if (ssl_err(s, ret) == -1) 228: goto fail; 229: } 230: } else { 231: while ((ret = SSL_connect(s->ssl)) <= 0) { 232: if (ssl_err(s, ret) == -1) 233: goto fail; 234: } 235: } 236: 237: /* Ready */ 238: return (0); 239: 240: fail: 241: /* Failed */ 242: errno = s->error; 243: return (-1); 244: } 245: 246: /* 247: * Handle an error return from an SSL I/O operation. 248: * 249: * It might be an error, or it might just be that more raw data 250: * needs to be read or written. Return -1 in the former case, 251: * otherwise return zero and wait for the readable or writable 252: * event as appropriate. 253: */ 254: static int 255: ssl_err(struct ssl_info *s, int ret) 256: { 257: int ret2; 258: 259: ret2 = SSL_get_error(s->ssl, ret); 260: switch (ret2) { 261: case SSL_ERROR_WANT_READ: 262: case SSL_ERROR_WANT_WRITE: 263: { 264: struct pollfd pfd; 265: int timeout; 266: int nfds; 267: 268: /* Set up read/write poll(2) event */ 269: memset(&pfd, 0, sizeof(pfd)); 270: pfd.fd = s->fd; 271: pfd.events = (ret2 == SSL_ERROR_WANT_READ) ? 272: POLLRDNORM : POLLWRNORM; 273: 274: /* Set up timeout */ 275: timeout = INFTIM; 276: if (s->timeout != 0) 277: timeout = s->timeout * 1000; 278: 279: /* Wait for readability or writability */ 280: if ((nfds = poll(&pfd, 1, timeout)) == -1) { 281: s->error = errno; 282: (*s->logger)(s->logarg, LOG_ERR, 283: "%s: %s", "poll", strerror(errno)); 284: goto fail; 285: } 286: 287: /* Check for timeout */ 288: if (nfds == 0) { 289: s->error = ETIMEDOUT; 290: goto fail; 291: } 292: 293: /* Done */ 294: return (0); 295: } 296: case SSL_ERROR_NONE: 297: return (0); 298: 299: case SSL_ERROR_SYSCALL: 300: ssl_log(s->logger, s->logarg); 301: if (ret != 0) { 302: s->error = errno; 303: (*s->logger)(s->logarg, LOG_ERR, 304: "SSL system error: %s", strerror(errno)); 305: goto fail; 306: } 307: /* fall through */ 308: 309: case SSL_ERROR_ZERO_RETURN: 310: (*s->logger)(s->logarg, LOG_ERR, "SSL connection closed"); 311: s->error = ECONNRESET; 312: goto fail; 313: 314: case SSL_ERROR_SSL: 315: ssl_log(s->logger, s->logarg); 316: s->error = EIO; 317: goto fail; 318: 319: case SSL_ERROR_WANT_X509_LOOKUP: /* should not happen */ 320: default: 321: ssl_log(s->logger, s->logarg); 322: (*s->logger)(s->logarg, LOG_ERR, 323: "unknown return %d from SSL_get_error", ret2); 324: s->error = ECONNABORTED; 325: goto fail; 326: } 327: 328: fail: 329: /* Got an error */ 330: errno = s->error; 331: return (-1); 332: } 333: 334: /* 335: * Log an SSL error. 336: */ 337: void 338: ssl_log(ssl_logger_t *logger, void *logarg) 339: { 340: char buf[200]; 341: const char *file; 342: const char *str; 343: const char *t; 344: int line, flags; 345: u_long e; 346: 347: while ((e = ERR_get_error_line_data(&file, &line, &str, &flags)) != 0) { 348: if (logger == NULL) 349: continue; 350: #if 0 351: (*logger)(logarg, LOG_ERR, "SSL: %s:%s:%d:%s\n", 352: ERR_error_string(e, buf), file, line, 353: (flags & ERR_TXT_STRING) ? str : ""); 354: #else 355: strlcpy(buf, "SSL: ", sizeof(buf)); 356: #if 0 357: /* Add library */ 358: if ((t = ERR_lib_error_string(e)) != NULL) { 359: strlcat(buf, t, sizeof(buf)); 360: strlcat(buf, ": ", sizeof(buf)); 361: } else { 362: snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), 363: "lib=%u: ", ERR_GET_LIB(e)); 364: } 365: #endif 366: 367: /* Add function */ 368: if ((t = ERR_func_error_string(e)) != NULL) { 369: strlcat(buf, t, sizeof(buf)); 370: strlcat(buf, ": ", sizeof(buf)); 371: } else { 372: snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), 373: "func=%u: ", ERR_GET_FUNC(e)); 374: } 375: 376: /* Add reason */ 377: if ((t = ERR_reason_error_string(e)) != NULL) { 378: strlcat(buf, t, sizeof(buf)); 379: } else { 380: snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), 381: "reason=%u", ERR_GET_REASON(e)); 382: } 383: 384: /* Add error text, if any */ 385: if ((flags & ERR_TXT_STRING) != 0) { 386: strlcat(buf, ": ", sizeof(buf)); 387: strlcat(buf, str, sizeof(buf)); 388: } 389: (*logger)(logarg, LOG_ERR, "%s", buf); 390: #endif 391: } 392: } 393: 394: static void 395: null_logger(void *arg, int sev, const char *fmt, ...) 396: { 1.1.1.2 ! misho 397: (void)arg; ! 398: (void)sev; ! 399: (void)fmt; ! 400: 1.1 misho 401: return; 402: } 403: