Module Name: src Committed By: mrg Date: Thu Jul 17 06:27:53 UTC 2014
Modified Files: src/libexec/httpd: bozohttpd.c bozohttpd.h ssl-bozo.c Log Message: rewrite much of the SSL code: - handle errors in many places they weren't properly - make SSL_accept() an error the main code notices - expand bozo_ssl_err() to include bozo_ssl_warn(), bozo_clear_ssl_queue() - remove empty bozo_ssl_flush() To generate a diff of this commit: cvs rdiff -u -r1.54 -r1.55 src/libexec/httpd/bozohttpd.c cvs rdiff -u -r1.32 -r1.33 src/libexec/httpd/bozohttpd.h cvs rdiff -u -r1.17 -r1.18 src/libexec/httpd/ssl-bozo.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/libexec/httpd/bozohttpd.c diff -u src/libexec/httpd/bozohttpd.c:1.54 src/libexec/httpd/bozohttpd.c:1.55 --- src/libexec/httpd/bozohttpd.c:1.54 Tue Jul 8 14:06:17 2014 +++ src/libexec/httpd/bozohttpd.c Thu Jul 17 06:27:52 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: bozohttpd.c,v 1.54 2014/07/08 14:06:17 mrg Exp $ */ +/* $NetBSD: bozohttpd.c,v 1.55 2014/07/17 06:27:52 mrg Exp $ */ /* $eterna: bozohttpd.c,v 1.178 2011/11/18 09:21:15 mrg Exp $ */ @@ -527,7 +527,8 @@ bozo_read_request(bozohttpd_t *httpd) */ if (bozo_daemon_fork(httpd)) return NULL; - bozo_ssl_accept(httpd); + if (bozo_ssl_accept(httpd)) + return NULL; request = bozomalloc(httpd, sizeof(*request)); memset(request, 0, sizeof(*request)); Index: src/libexec/httpd/bozohttpd.h diff -u src/libexec/httpd/bozohttpd.h:1.32 src/libexec/httpd/bozohttpd.h:1.33 --- src/libexec/httpd/bozohttpd.h:1.32 Sun Feb 9 01:46:10 2014 +++ src/libexec/httpd/bozohttpd.h Thu Jul 17 06:27:52 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: bozohttpd.h,v 1.32 2014/02/09 01:46:10 mrg Exp $ */ +/* $NetBSD: bozohttpd.h,v 1.33 2014/07/17 06:27:52 mrg Exp $ */ /* $eterna: bozohttpd.h,v 1.39 2011/11/18 09:21:15 mrg Exp $ */ @@ -235,12 +235,12 @@ char *bozostrdup(bozohttpd_t *, const ch #ifdef NO_SSL_SUPPORT #define bozo_ssl_set_opts(w, x, y) do { /* nothing */ } while (0) #define bozo_ssl_init(x) do { /* nothing */ } while (0) -#define bozo_ssl_accept(x) do { /* nothing */ } while (0) +#define bozo_ssl_accept(x) (0) #define bozo_ssl_destroy(x) do { /* nothing */ } while (0) #else void bozo_ssl_set_opts(bozohttpd_t *, const char *, const char *); void bozo_ssl_init(bozohttpd_t *); -void bozo_ssl_accept(bozohttpd_t *); +int bozo_ssl_accept(bozohttpd_t *); void bozo_ssl_destroy(bozohttpd_t *); #endif Index: src/libexec/httpd/ssl-bozo.c diff -u src/libexec/httpd/ssl-bozo.c:1.17 src/libexec/httpd/ssl-bozo.c:1.18 --- src/libexec/httpd/ssl-bozo.c:1.17 Thu Jul 17 06:14:46 2014 +++ src/libexec/httpd/ssl-bozo.c Thu Jul 17 06:27:52 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: ssl-bozo.c,v 1.17 2014/07/17 06:14:46 mrg Exp $ */ +/* $NetBSD: ssl-bozo.c,v 1.18 2014/07/17 06:27:52 mrg Exp $ */ /* $eterna: ssl-bozo.c,v 1.15 2011/11/18 09:21:15 mrg Exp $ */ @@ -30,7 +30,7 @@ * */ -/* this code implements SSL for bozohttpd */ +/* this code implements SSL and backend IO for bozohttpd */ #include <stdarg.h> #include <stdio.h> @@ -58,26 +58,13 @@ typedef struct sslinfo_t { } sslinfo_t; /* - * bozo_ssl_err - * - * bozo_ssl_err works just like bozo_err except in addition to printing - * the error provided by the caller at the point of error it pops and - * prints all errors from the SSL error queue. + * bozo_clear_ssl_queue: print the contents of the SSL error queue */ -BOZO_PRINTFLIKE(3, 4) BOZO_DEAD static void -bozo_ssl_err(bozohttpd_t *httpd, int code, const char *fmt, ...) +static void +bozo_clear_ssl_queue(bozohttpd_t *httpd) { - va_list ap; + unsigned long sslcode = ERR_get_error(); - va_start(ap, fmt); - if (httpd->logstderr || isatty(STDERR_FILENO)) { - vfprintf(stderr, fmt, ap); - fputs("\n", stderr); - } else - vsyslog(LOG_ERR, fmt, ap); - va_end(ap); - - unsigned int sslcode = ERR_get_error(); do { static const char sslfmt[] = "SSL Error: %s:%s:%s"; @@ -93,19 +80,77 @@ bozo_ssl_err(bozohttpd_t *httpd, int cod ERR_reason_error_string(sslcode)); } } while (0 != (sslcode = ERR_get_error())); +} + +/* + * bozo_ssl_warn works just like bozo_warn, plus the SSL error queue + */ +BOZO_PRINTFLIKE(2, 3) static void +bozo_ssl_warn(bozohttpd_t *httpd, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + if (httpd->logstderr || isatty(STDERR_FILENO)) { + vfprintf(stderr, fmt, ap); + fputs("\n", stderr); + } else + vsyslog(LOG_ERR, fmt, ap); + va_end(ap); + + bozo_clear_ssl_queue(httpd); +} + + +/* + * bozo_ssl_err works just like bozo_err, plus the SSL error queue + */ +BOZO_PRINTFLIKE(3, 4) BOZO_DEAD static void +bozo_ssl_err(bozohttpd_t *httpd, int code, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + if (httpd->logstderr || isatty(STDERR_FILENO)) { + vfprintf(stderr, fmt, ap); + fputs("\n", stderr); + } else + vsyslog(LOG_ERR, fmt, ap); + va_end(ap); + + bozo_clear_ssl_queue(httpd); exit(code); } +/* + * bozo_check_error_queue: print warnings if the error isn't expected + */ +static void +bozo_check_error_queue(bozohttpd_t *httpd, const char *tag, int ret) +{ + if (ret > 0) + return; + + const sslinfo_t *sslinfo = httpd->sslinfo; + const int sslerr = SSL_get_error(sslinfo->bozossl, ret); + + if (sslerr != SSL_ERROR_ZERO_RETURN && + sslerr != SSL_ERROR_SYSCALL && + sslerr != SSL_ERROR_NONE) + bozo_ssl_warn(httpd, "%s: SSL_ERROR %d", tag, sslerr); +} + static BOZO_PRINTFLIKE(2, 0) int bozo_ssl_printf(bozohttpd_t *httpd, const char * fmt, va_list ap) { - const sslinfo_t *sslinfo = httpd->sslinfo; - char *buf; - int nbytes; + char *buf; + int nbytes; - /* XXX we need more elegant/proper handling of SSL_write return */ - if ((nbytes = vasprintf(&buf, fmt, ap)) != -1) - SSL_write(sslinfo->bozossl, buf, nbytes); + if ((nbytes = vasprintf(&buf, fmt, ap)) != -1) { + const sslinfo_t *sslinfo = httpd->sslinfo; + int ret = SSL_write(sslinfo->bozossl, buf, nbytes); + bozo_check_error_queue(httpd, "write", ret); + } free(buf); @@ -116,42 +161,26 @@ static ssize_t bozo_ssl_read(bozohttpd_t *httpd, int fd, void *buf, size_t nbytes) { const sslinfo_t *sslinfo = httpd->sslinfo; - ssize_t rbytes; + int ret; USE_ARG(fd); - /* XXX we need elegant/proper handling of SSL_read return */ - rbytes = (ssize_t)SSL_read(sslinfo->bozossl, buf, (int)nbytes); - if (rbytes < 1) { - if (SSL_get_error(sslinfo->bozossl, rbytes) == - SSL_ERROR_WANT_READ) - bozo_warn(httpd, "SSL_ERROR_WANT_READ"); - else - bozo_warn(httpd, "SSL_ERROR OTHER"); - } + ret = SSL_read(sslinfo->bozossl, buf, (int)nbytes); + bozo_check_error_queue(httpd, "read", ret); - return rbytes; + return (ssize_t)ret; } static ssize_t bozo_ssl_write(bozohttpd_t *httpd, int fd, const void *buf, size_t nbytes) { const sslinfo_t *sslinfo = httpd->sslinfo; - ssize_t wbytes; + int ret; USE_ARG(fd); - /* XXX we need elegant/proper handling of SSL_write return */ - wbytes = (ssize_t)SSL_write(sslinfo->bozossl, buf, (int)nbytes); + ret = SSL_write(sslinfo->bozossl, buf, (int)nbytes); + bozo_check_error_queue(httpd, "write", ret); - return wbytes; -} - -static int -bozo_ssl_flush(bozohttpd_t *httpd, FILE *fp) -{ - USE_ARG(httpd); - USE_ARG(fp); - /* nothing to see here, move right along */ - return 0; + return (ssize_t)ret; } void @@ -167,7 +196,6 @@ bozo_ssl_init(bozohttpd_t *httpd) sslinfo->ssl_method = SSLv23_server_method(); sslinfo->ssl_context = SSL_CTX_new(sslinfo->ssl_method); - /* XXX we need to learn how to check the SSL stack for more info */ if (NULL == sslinfo->ssl_context) bozo_ssl_err(httpd, EXIT_FAILURE, "SSL context creation failed"); @@ -190,17 +218,28 @@ bozo_ssl_init(bozohttpd_t *httpd) "Check private key failed"); } -void +/* + * returns non-zero for failure + */ +int bozo_ssl_accept(bozohttpd_t *httpd) { sslinfo_t *sslinfo = httpd->sslinfo; - if (sslinfo != NULL && sslinfo->ssl_context) { - sslinfo->bozossl = SSL_new(sslinfo->ssl_context); - SSL_set_rfd(sslinfo->bozossl, 0); - SSL_set_wfd(sslinfo->bozossl, 1); - SSL_accept(sslinfo->bozossl); - } + if (sslinfo == NULL || !sslinfo->ssl_context) + return 0; + + sslinfo->bozossl = SSL_new(sslinfo->ssl_context); + if (sslinfo->bozossl == NULL) + bozo_err(httpd, 1, "SSL_new failed"); + + SSL_set_rfd(sslinfo->bozossl, 0); + SSL_set_wfd(sslinfo->bozossl, 1); + + const int ret = SSL_accept(sslinfo->bozossl); + bozo_check_error_queue(httpd, "accept", ret); + + return ret != 1; } void @@ -219,9 +258,8 @@ bozo_ssl_set_opts(bozohttpd_t *httpd, co if (sslinfo == NULL) { sslinfo = bozomalloc(httpd, sizeof(*sslinfo)); - if (sslinfo == NULL) { + if (sslinfo == NULL) bozo_err(httpd, 1, "sslinfo allocation failed"); - } httpd->sslinfo = sslinfo; } sslinfo->certificate_file = strdup(cert); @@ -277,7 +315,7 @@ bozo_flush(bozohttpd_t *httpd, FILE *fp) { #ifndef NO_SSL_SUPPORT if (httpd->sslinfo) - return bozo_ssl_flush(httpd, fp); + return 0; #endif return fflush(fp); }