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);
 }

Reply via email to