Module Name: src Committed By: mrg Date: Wed Nov 21 09:37:02 UTC 2018
Modified Files: src/libexec/httpd: CHANGES auth-bozo.c bozohttpd.c bozohttpd.h src/libexec/httpd/testsuite: Makefile html_cmp test-bigfile test-simple Log Message: - move special files defines into bozohttpd.h, so we can ... - consolidate all the special file checks into bozo_check_special_files() so that all builds check the same list of special files, regardless of build options. - convert "(void)bozo_http_error(...); return -1;" into plain "return bozo_http_error(...);" - fix the call to bozo_check_special_files() to be used on all input types. part of the fixes for failure to reject access to /.htpasswd as reported by JP on tech-security. - use warn_unused_result attribute on bozo_check_special_files(), and fix the failures to return failure. second part of the htpasswd access fix. - update testsuite to use a fixed fake hostname. call this bozohttpd 20181121. To generate a diff of this commit: cvs rdiff -u -r1.27 -r1.28 src/libexec/httpd/CHANGES cvs rdiff -u -r1.20 -r1.21 src/libexec/httpd/auth-bozo.c cvs rdiff -u -r1.90 -r1.91 src/libexec/httpd/bozohttpd.c cvs rdiff -u -r1.54 -r1.55 src/libexec/httpd/bozohttpd.h cvs rdiff -u -r1.10 -r1.11 src/libexec/httpd/testsuite/Makefile cvs rdiff -u -r1.5 -r1.6 src/libexec/httpd/testsuite/html_cmp cvs rdiff -u -r1.4 -r1.5 src/libexec/httpd/testsuite/test-bigfile \ src/libexec/httpd/testsuite/test-simple 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/CHANGES diff -u src/libexec/httpd/CHANGES:1.27 src/libexec/httpd/CHANGES:1.28 --- src/libexec/httpd/CHANGES:1.27 Tue Nov 20 01:06:46 2018 +++ src/libexec/httpd/CHANGES Wed Nov 21 09:37:02 2018 @@ -1,6 +1,6 @@ -$NetBSD: CHANGES,v 1.27 2018/11/20 01:06:46 mrg Exp $ +$NetBSD: CHANGES,v 1.28 2018/11/21 09:37:02 mrg Exp $ -changes in bozohttpd 20181118: +changes in bozohttpd 20181121: o add url remap support via .bzremap file, from mar...@netbsd.org o handle redirections for any protocol, not just http: o fix a denial of service attack against header contents, which @@ -9,6 +9,7 @@ changes in bozohttpd 20181118: initial line, each header, and the total time spent o add -T option to expose new timeout settings o minor RFC fixes related to timeout handling + o fix special file (.htpasswd, .bz*) bypass. reported by JP. changes in bozohttpd 20170201: o fix an infinite loop in cgi processing Index: src/libexec/httpd/auth-bozo.c diff -u src/libexec/httpd/auth-bozo.c:1.20 src/libexec/httpd/auth-bozo.c:1.21 --- src/libexec/httpd/auth-bozo.c:1.20 Tue Nov 20 01:06:46 2018 +++ src/libexec/httpd/auth-bozo.c Wed Nov 21 09:37:02 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: auth-bozo.c,v 1.20 2018/11/20 01:06:46 mrg Exp $ */ +/* $NetBSD: auth-bozo.c,v 1.21 2018/11/21 09:37:02 mrg Exp $ */ /* $eterna: auth-bozo.c,v 1.17 2011/11/18 09:21:15 mrg Exp $ */ @@ -42,10 +42,6 @@ #include "bozohttpd.h" -#ifndef AUTH_FILE -#define AUTH_FILE ".htpasswd" -#endif - static ssize_t base64_decode(const unsigned char *, size_t, unsigned char *, size_t); @@ -68,7 +64,6 @@ bozo_auth_check(bozo_httpreq_t *request, strcpy(dir, "."); else { *basename++ = '\0'; - /* ensure basename(file) != AUTH_FILE */ if (bozo_check_special_files(request, basename)) return 1; } @@ -173,18 +168,6 @@ bozo_auth_check_headers(bozo_httpreq_t * return 0; } -int -bozo_auth_check_special_files(bozo_httpreq_t *request, - const char *name) -{ - bozohttpd_t *httpd = request->hr_httpd; - - if (strcmp(name, AUTH_FILE) == 0) - return bozo_http_error(httpd, 403, request, - "no permission to open authfile"); - return 0; -} - void bozo_auth_check_401(bozo_httpreq_t *request, int code) { Index: src/libexec/httpd/bozohttpd.c diff -u src/libexec/httpd/bozohttpd.c:1.90 src/libexec/httpd/bozohttpd.c:1.91 --- src/libexec/httpd/bozohttpd.c:1.90 Tue Nov 20 01:06:46 2018 +++ src/libexec/httpd/bozohttpd.c Wed Nov 21 09:37:02 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: bozohttpd.c,v 1.90 2018/11/20 01:06:46 mrg Exp $ */ +/* $NetBSD: bozohttpd.c,v 1.91 2018/11/21 09:37:02 mrg Exp $ */ /* $eterna: bozohttpd.c,v 1.178 2011/11/18 09:21:15 mrg Exp $ */ @@ -109,26 +109,9 @@ #define INDEX_HTML "index.html" #endif #ifndef SERVER_SOFTWARE -#define SERVER_SOFTWARE "bozohttpd/20181119" -#endif -#ifndef DIRECT_ACCESS_FILE -#define DIRECT_ACCESS_FILE ".bzdirect" -#endif -#ifndef REDIRECT_FILE -#define REDIRECT_FILE ".bzredirect" -#endif -#ifndef ABSREDIRECT_FILE -#define ABSREDIRECT_FILE ".bzabsredirect" -#endif -#ifndef REMAP_FILE -#define REMAP_FILE ".bzremap" +#define SERVER_SOFTWARE "bozohttpd/20181121" #endif -/* - * When you add some .bz* file, make sure to also check it in - * bozo_check_special_files() - */ - #ifndef PUBLIC_HTML #define PUBLIC_HTML "public_html" #endif @@ -696,7 +679,6 @@ bozo_read_request(bozohttpd_t *httpd) sa.sa_flags = 0; sigaction(SIGALRM, &sa, NULL); - if (clock_gettime(CLOCK_MONOTONIC, &ots) != 0) { (void)bozo_http_error(httpd, 500, NULL, "clock_gettime failed"); @@ -1466,32 +1448,33 @@ check_bzredirect(bozo_httpreq_t *request * if this pathname is really a directory, but doesn't end in /, * use it as the directory to look for the redir file. */ - if((size_t)snprintf(dir, sizeof(dir), "%s", request->hr_file + 1) >= - sizeof(dir)) { - bozo_http_error(httpd, 404, request, + if ((size_t)snprintf(dir, sizeof(dir), "%s", request->hr_file + 1) >= + sizeof(dir)) + return bozo_http_error(httpd, 404, request, "file path too long"); - return -1; - } debug((httpd, DEBUG_FAT, "check_bzredirect: dir %s", dir)); basename = strrchr(dir, '/'); if ((!basename || basename[1] != '\0') && lstat(dir, &sb) == 0 && S_ISDIR(sb.st_mode)) { strcpy(path, dir); + basename = dir; } else if (basename == NULL) { strcpy(path, "."); strcpy(dir, ""); + basename = request->hr_file + 1; } else { *basename++ = '\0'; - bozo_check_special_files(request, basename); strcpy(path, dir); } + if (bozo_check_special_files(request, basename)) + return -1; debug((httpd, DEBUG_FAT, "check_bzredirect: path %s", path)); if ((size_t)snprintf(redir, sizeof(redir), "%s/%s", path, REDIRECT_FILE) >= sizeof(redir)) { - bozo_http_error(httpd, 404, request, + return bozo_http_error(httpd, 404, request, "redirectfile path too long"); return -1; } @@ -1502,9 +1485,8 @@ check_bzredirect(bozo_httpreq_t *request } else { if((size_t)snprintf(redir, sizeof(redir), "%s/%s", path, ABSREDIRECT_FILE) >= sizeof(redir)) { - bozo_http_error(httpd, 404, request, + return bozo_http_error(httpd, 404, request, "redirectfile path too long"); - return -1; } if (lstat(redir, &sb) < 0 || !S_ISLNK(sb.st_mode)) return 0; @@ -1528,9 +1510,8 @@ check_bzredirect(bozo_httpreq_t *request if (!absolute && redirpath[0] != '/') { if ((size_t)snprintf(finalredir = redir, sizeof(redir), "%s%s/%s", (strlen(dir) > 0 ? "/" : ""), dir, redirpath) >= sizeof(redir)) { - bozo_http_error(httpd, 404, request, + return bozo_http_error(httpd, 404, request, "redirect path too long"); - return -1; } } else finalredir = redirpath; @@ -1566,21 +1547,15 @@ bozo_decode_url_percent(bozo_httpreq_t * debug((httpd, DEBUG_EXPLODING, "fu_%%: got s == %%, s[1]s[2] == %c%c", s[1], s[2])); - if (s[1] == '\0' || s[2] == '\0') { - (void)bozo_http_error(httpd, 400, request, + if (s[1] == '\0' || s[2] == '\0') + return bozo_http_error(httpd, 400, request, "percent hack missing two chars afterwards"); - return 1; - } - if (s[1] == '0' && s[2] == '0') { - (void)bozo_http_error(httpd, 404, request, - "percent hack was %00"); - return 1; - } - if (s[1] == '2' && s[2] == 'f') { - (void)bozo_http_error(httpd, 404, request, - "percent hack was %2f (/)"); - return 1; - } + if (s[1] == '0' && s[2] == '0') + return bozo_http_error(httpd, 404, request, + "percent hack was %00"); + if (s[1] == '2' && s[2] == 'f') + return bozo_http_error(httpd, 404, request, + "percent hack was %2f (/)"); buf[0] = *++s; buf[1] = *++s; @@ -1589,11 +1564,9 @@ bozo_decode_url_percent(bozo_httpreq_t * *t = (char)strtol(buf, NULL, 16); debug((httpd, DEBUG_EXPLODING, "fu_%%: strtol put '%02x' into *t", *t)); - if (*t++ == '\0') { - (void)bozo_http_error(httpd, 400, request, - "percent hack got a 0 back"); - return 1; - } + if (*t++ == '\0') + return bozo_http_error(httpd, 400, request, + "percent hack got a 0 back"); while (*s && *s != '%') { if (end && s >= end) @@ -1685,7 +1658,9 @@ transform_request(bozo_httpreq_t *reques switch (check_bzredirect(request)) { case -1: goto bad_done; - case 1: + case 0: + break; + default: return 0; } @@ -1963,7 +1938,11 @@ bozo_check_special_files(bozo_httpreq_t if (strcmp(name, REMAP_FILE) == 0) return bozo_http_error(httpd, 403, request, "no permission to open redirect file"); - return bozo_auth_check_special_files(request, name); + if (strcmp(name, AUTH_FILE) == 0) + return bozo_http_error(httpd, 403, request, + "no permission to open authfile"); + + return 0; } /* generic header printing routine */ Index: src/libexec/httpd/bozohttpd.h diff -u src/libexec/httpd/bozohttpd.h:1.54 src/libexec/httpd/bozohttpd.h:1.55 --- src/libexec/httpd/bozohttpd.h:1.54 Tue Nov 20 01:23:06 2018 +++ src/libexec/httpd/bozohttpd.h Wed Nov 21 09:37:02 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: bozohttpd.h,v 1.54 2018/11/20 01:23:06 mrg Exp $ */ +/* $NetBSD: bozohttpd.h,v 1.55 2018/11/21 09:37:02 mrg Exp $ */ /* $eterna: bozohttpd.h,v 1.39 2011/11/18 09:21:15 mrg Exp $ */ @@ -217,9 +217,11 @@ typedef struct bozoprefs_t { #if (defined(__GNUC__) && __GNUC__ >= 3) || defined(__lint__) #define BOZO_PRINTFLIKE(x,y) __attribute__((__format__(__printf__, x,y))) #define BOZO_DEAD __attribute__((__noreturn__)) +#define BOZO_CHECKRET __attribute__((__warn_unused_result__)) #else #define BOZO_PRINTFLIKE(x,y) #define BOZO_DEAD +#define BOZO_CHECKRET #endif #ifdef NO_DEBUG @@ -231,9 +233,33 @@ void debug__(bozohttpd_t *, int, const c #define have_debug (1) #endif /* NO_DEBUG */ +/* + * bozohttpd special files. avoid serving these out. + * + * When you add some .bz* file, make sure to also check it in + * bozo_check_special_files() + */ + +#ifndef DIRECT_ACCESS_FILE +#define DIRECT_ACCESS_FILE ".bzdirect" +#endif +#ifndef REDIRECT_FILE +#define REDIRECT_FILE ".bzredirect" +#endif +#ifndef ABSREDIRECT_FILE +#define ABSREDIRECT_FILE ".bzabsredirect" +#endif +#ifndef REMAP_FILE +#define REMAP_FILE ".bzremap" +#endif +#ifndef AUTH_FILE +#define AUTH_FILE ".htpasswd" +#endif + +/* be sure to always return this error up */ int bozo_http_error(bozohttpd_t *, int, bozo_httpreq_t *, const char *); -int bozo_check_special_files(bozo_httpreq_t *, const char *); +int bozo_check_special_files(bozo_httpreq_t *, const char *) BOZO_CHECKRET; char *bozo_http_date(char *, size_t); void bozo_print_header(bozo_httpreq_t *, struct stat *, const char *, const char *); @@ -284,7 +310,6 @@ void bozo_auth_init(bozo_httpreq_t *); int bozo_auth_check(bozo_httpreq_t *, const char *); void bozo_auth_cleanup(bozo_httpreq_t *); int bozo_auth_check_headers(bozo_httpreq_t *, char *, char *, ssize_t); -int bozo_auth_check_special_files(bozo_httpreq_t *, const char *); void bozo_auth_check_401(bozo_httpreq_t *, int); void bozo_auth_cgi_setenv(bozo_httpreq_t *, char ***); int bozo_auth_cgi_count(bozo_httpreq_t *); @@ -293,7 +318,6 @@ int bozo_auth_cgi_count(bozo_httpreq_t * #define bozo_auth_check(x, y) (0) #define bozo_auth_cleanup(x) bozo_noop #define bozo_auth_check_headers(y, z, a, b) (0) -#define bozo_auth_check_special_files(x, y) (0) #define bozo_auth_check_401(x, y) bozo_noop #define bozo_auth_cgi_setenv(x, y) bozo_noop #define bozo_auth_cgi_count(x) (0) Index: src/libexec/httpd/testsuite/Makefile diff -u src/libexec/httpd/testsuite/Makefile:1.10 src/libexec/httpd/testsuite/Makefile:1.11 --- src/libexec/httpd/testsuite/Makefile:1.10 Tue Nov 20 01:06:46 2018 +++ src/libexec/httpd/testsuite/Makefile Wed Nov 21 09:37:02 2018 @@ -9,6 +9,7 @@ BOZOHTTPD?= ../debug/bozohttpd-debug WGET?= wget DATA?= $(.CURDIR)/data VERBOSE?= yes +HOST?= test.eterna .if ${VERBOSE} != "yes" SILENT= @ @@ -27,17 +28,17 @@ check: check-simple check-cgi check-bigf check-simple: .for a in $(SIMPLETESTS) - ${SILENT}$(.CURDIR)/test-simple "$a" "${BOZOHTTPD}" "${DATA}" "${.CURDIR}" "${VERBOSE}" + ${SILENT}$(.CURDIR)/test-simple "$a" "${BOZOHTTPD}" "${DATA}" "${.CURDIR}" "${VERBOSE}" "${HOST}" .endfor check-cgi: .for a in $(CGITESTS) - ${SILENT}$(.CURDIR)/test-simple "$a" "${BOZOHTTPD}" "${DATA}" "${.CURDIR}" "${VERBOSE}" -c "${.CURDIR}/cgi-bin" + ${SILENT}$(.CURDIR)/test-simple "$a" "${BOZOHTTPD}" "${DATA}" "${.CURDIR}" "${VERBOSE}" "${HOST}" -c "${.CURDIR}/cgi-bin" .endfor check-bigfile: .for a in $(BIGFILETESTS) - ${SILENT}$(.CURDIR)/test-bigfile "$a" "${BOZOHTTPD}" "${WGET}" "${DATA}" "${VERBOSE}" + ${SILENT}$(.CURDIR)/test-bigfile "$a" "${BOZOHTTPD}" "${WGET}" "${DATA}" "${VERBOSE}" "${HOST}" .endfor .include <bsd.obj.mk> Index: src/libexec/httpd/testsuite/html_cmp diff -u src/libexec/httpd/testsuite/html_cmp:1.5 src/libexec/httpd/testsuite/html_cmp:1.6 --- src/libexec/httpd/testsuite/html_cmp:1.5 Tue Dec 27 12:09:19 2016 +++ src/libexec/httpd/testsuite/html_cmp Wed Nov 21 09:37:02 2018 @@ -22,6 +22,7 @@ h=`hostname || uname -n` sedcmd="s/^Date: .*/Date: nowish/; s/^Last-Modified: .*/Last-Modified: nowish/; s/[a-zA-Z0-9-]*\.eterna\.com\.au/$h/g; + s/[a-zA-Z0-9-]*\.eterna23\.net/$h/g; s/^Server: .*/^Server: bozotic HTTP server version 5.08/; s/^Content-Length: .*/Content-Length: 223/;" Index: src/libexec/httpd/testsuite/test-bigfile diff -u src/libexec/httpd/testsuite/test-bigfile:1.4 src/libexec/httpd/testsuite/test-bigfile:1.5 --- src/libexec/httpd/testsuite/test-bigfile:1.4 Tue Jan 31 14:33:54 2017 +++ src/libexec/httpd/testsuite/test-bigfile Wed Nov 21 09:37:02 2018 @@ -1,11 +1,12 @@ #! /bin/sh -# $NetBSD: test-bigfile,v 1.4 2017/01/31 14:33:54 mrg Exp $ +# $NetBSD: test-bigfile,v 1.5 2018/11/21 09:37:02 mrg Exp $ -test="$1" # partial4000 or partial8000 -bozohttpd="$2" -wget="$3" -datadir="$4" -verbose="$5" +test="$1"; shift # partial4000 or partial8000 +bozohttpd="$1"; shift +wget="$1"; shift +datadir="$1"; shift +verbose="$1"; shift +host="$1"; shift tmperr="tmp.$test.err" @@ -21,7 +22,7 @@ bozotestport=11111 cp "${datadir}/bigfile.${test}" ./bigfile # fire up bozohttpd -${bozohttpd} -b -b -I ${bozotestport} -n -s -f "${datadir}" & +${bozohttpd} -b -b -I ${bozotestport} -n -s -f "$@" "${datadir}" "${host}" & bozopid=$! "${wget}" -c http://localhost:${bozotestport}/bigfile Index: src/libexec/httpd/testsuite/test-simple diff -u src/libexec/httpd/testsuite/test-simple:1.4 src/libexec/httpd/testsuite/test-simple:1.5 --- src/libexec/httpd/testsuite/test-simple:1.4 Tue Jan 31 14:33:54 2017 +++ src/libexec/httpd/testsuite/test-simple Wed Nov 21 09:37:02 2018 @@ -1,11 +1,12 @@ #! /bin/sh -# $NetBSD: test-simple,v 1.4 2017/01/31 14:33:54 mrg Exp $ +# $NetBSD: test-simple,v 1.5 2018/11/21 09:37:02 mrg Exp $ test="$1"; shift bozohttpd="$1"; shift datadir="$1"; shift curdir="$1"; shift verbose="$1"; shift +host="$1"; shift in="$curdir/$test.in" out="$curdir/$test.out" @@ -20,7 +21,7 @@ fi bozotestport=11111 -${bozohttpd} "$@" "${datadir}" < "$in" > "$tmpout" +${bozohttpd} "$@" "${datadir}" "${host}" < "$in" > "$tmpout" if "$curdir/html_cmp" cmp "$out" "$tmpout"; then exit 0 else