pkgsrc-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

pkg/60761: www/thttpd: three unfixed CVEs, one whose patch never worked, and a world-readable log



>Number:         60761
>Category:       pkg
>Synopsis:       www/thttpd: three unfixed CVEs, one whose patch never worked, and a world-readable log
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    pkg-manager
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue Sep 22 03:10:00 +0000 2026
>Originator:     Showta Ishizaki
>Release:        pkgsrc CVS as of 2026-09-22
>Organization:
>Environment:
System: NetBSD 10.1 i386
Architecture: i386
Machine: i386
>Description:
	www/thttpd is at 2.29, the last release ACME made.  Three of the CVEs
	filed against it are unfixed, and the patch for a fourth has never
	worked.

	CVE-2012-5640 -- crypt(3) returns NULL for a salt it does not
	recognise, and auth_check2() hands the result straight to strcmp().
	The salt comes from a user-written .htpasswd, so one malformed line
	is enough to kill the server on the next request for that directory.
	Which libc returns NULL varies: OpenBSD and illumos do, while NetBSD
	and current Linux return "*0" instead.  extras/htpasswd.c has the
	same unchecked result, there passed to fprintf("%s").

	CVE-2007-0158 -- five places index with length-1 without checking
	the length.  Three are in expand_symlinks(): a path of only slashes
	under no_symlink_check reaches checked[-1]; an empty path reaches
	rest[-1]; and a zero-length symlink target in the served tree
	reaches lnk[-1].  The fourth is in auth_check2(), where fgets()
	returns a line beginning with a NUL byte and line[-1] is read, which
	is reachable the same way CVE-2012-5640 is.  The fifth is in
	thttpd.c: max_connects is fdwatch_get_nfiles() - SPARE_FDS with no
	lower bound, so a descriptor limit of 10 leaves it at 0 and
	connects[-1] is written.

	CVE-2009-4491 -- the request line, the headers and the values
	derived from them are written to the log and to syslog exactly as
	the client sent them, so a request can place terminal escape
	sequences in the log.  This is not only make_log_entry(): eighteen
	call sites write a client-controlled value, including the
	"unparsable time" pair, check_referrer(), and the messages about a
	path outside the web tree.  No other packaging I looked at carries a
	fix for this one, and it is not in ACME's 2.30 changelog either.

	CVE-2005-3124 -- syslogtocern wrote to /tmp/stc1.$$, a name that can
	be worked out in advance.  pkgsrc patched that in 2005, in patch-ag,
	replacing the name with mktemp(1).  But the line the patch
	substitutes carries a stray second backtick:

	  tmp1=``mktemp -t stc1.XXXXXX` || { echo ... }

	so the script it produces does not parse.  "sh -n" reports an
	unmatched backtick, and running the installed one gives

	  syslogtocern: 34: Syntax error: "||" unexpected

	before it does anything.  The fix has therefore not been in effect
	since it went in, and pkg-vulnerabilities has said "fixed in
	2.25bnb4" for twenty years.

	Three more things, none of them a CVE, kept in separate patches:

	The access log is created world-readable.  Both places that open it
	use fopen(logfile, "a"), so a log that does not exist yet is created
	0644 under the usual umask.  Every line holds the request line, the
	Referer, the User-Agent, and on an authenticated directory the
	remote user name.  It matters most after log rotation, where thttpd
	recreates the file on SIGHUP.

	extras/htpasswd.c reads lines into MAX_STRING_LEN (256) buffers.
	A modern crypt(3) hash runs to about a hundred characters, so a line
	written by another tool does not fit, and my_getline() truncates it
	without saying so; the remainder is then read as the next line, so
	adding a user to an existing file corrupts it.  The same file leaves
	pass uninitialised when fgets() fails, and reads pass[-1] for a line
	that starts with a NUL byte.

	The configure script's test programs declare main() without a return
	type.  C99 removed implicit int, so on a compiler that rejects it the
	very first test fails with "C compiler cannot create executables".
	gcc 14 and clang 16 and later are in that state; it is what stops the
	build on Debian 13.

>How-To-Repeat:
	For CVE-2012-5640, on a box whose crypt(3) returns NULL (OpenBSD,
	illumos), put a line with a salt it does not know into a .htpasswd
	and request the directory:

	  printf 'bob:$9$notasalt\n' > htdocs/priv/.htpasswd
	  thttpd -p 8080 -d htdocs -D -nos &
	  curl -u bob:pw http://127.0.0.1:8080/priv/

	The server is gone afterwards.  On a libc that returns "*0" the same
	request survives, which is why the fix is worth having on all of
	them rather than only where it crashes today.

	For CVE-2009-4491, one request is enough:

	  curl -H "$(printf 'Referer: R\033]0;X\007')" http://127.0.0.1:8080/x

	and the escape sequence is in the log file as sent.

	For CVE-2007-0158, a zero-length symlink in the served tree, or a
	.htpasswd line that begins with a NUL byte:

	  ln -s "" htdocs/empty && curl http://127.0.0.1:8080/empty
	  printf '\000bob:x\n' > htdocs/priv/.htpasswd
	  curl -u bob:x http://127.0.0.1:8080/priv/

	Built with -fsanitize=address, the first reports an out-of-bounds
	read in expand_symlinks() and the second one in auth_check2().
	Linux cannot create the empty symlink, so there the second is the
	one to use.

	For CVE-2005-3124, no request is needed:

	  sh -n /usr/pkg/sbin/syslogtocern
	  syslogtocern: 34: Syntax error: "||" unexpected

>Fix:
	The diff below is against CVS as of 2026-09-22 (www/thttpd/Makefile
	rev 1.54, distinfo rev 1.21, PLIST rev 1.6, doc/pkg-vulnerabilities
	rev 1.794).  It applies with "patch -p0" from the top of the pkgsrc
	tree.  Because the patches are renamed, the old names need cvs rm
	and the new files need cvs add; MESSAGE needs cvs rm too, since
	patch cannot delete a file.

	  cvs rm  www/thttpd/MESSAGE
	  cvs rm  www/thttpd/patches/patch-a[abcdfg]
	  cvs add www/thttpd/files/README.pkgsrc
	  cvs add www/thttpd/patches/patch-CVE-2005-3124
	  cvs add www/thttpd/patches/patch-CVE-2007-0158
	  cvs add www/thttpd/patches/patch-CVE-2009-4491
	  cvs add www/thttpd/patches/patch-CVE-2012-5640
	  cvs add www/thttpd/patches/patch-Makefile.in
	  cvs add www/thttpd/patches/patch-cgi-src_Makefile.in
	  cvs add www/thttpd/patches/patch-configure
	  cvs add www/thttpd/patches/patch-extras_Makefile.in
	  cvs add www/thttpd/patches/patch-extras_htpasswd.c
	  cvs add www/thttpd/patches/patch-index.html
	  cvs add www/thttpd/patches/patch-libhttpd.c
	  cvs add www/thttpd/patches/patch-mmc.c
	  cvs add www/thttpd/patches/patch-thttpd.c

	The four CVEs get one patch each, so that each can be read against
	its advisory.  That means four patches touch libhttpd.c, and they
	are named so that they apply in the right order.

	The six two-letter patches are renamed after the file they touch and
	regenerated from a pristine 2.29, and all of them gain the
	description pkglint asks for.  patch-ag becomes patch-CVE-2005-3124,
	since that is what it is for; its stray backtick is gone, and with
	it gone the script parses and converts a syslog file into
	CERN-format access_log and error_log as the manual page says.

	patch-mmc.c is worth a word.  It turns off mmap on NetBSD up to
	1.5L, and the reason is in PR pkg/25487: before UBC arrived, mmap
	and read were not kept in sync, so thttpd went on serving the old
	contents of an edited page until it was restarted.

	Three patches that are not CVEs:

	  patches/patch-thttpd.c          the log is created 0640, not 0644
	  patches/patch-extras_htpasswd.c line length, and the fgets checks
	  patches/patch-configure         C99 main()

	patch-libhttpd.c is the one I would flag.  It is not a security fix
	and not an underflow -- the stock "i > 0" test already prevents the
	index going negative.  What it changes is that when PATH_INFO is the
	whole of origfilename, the pathinfo part is now removed from it as
	the comment there says it should be.  FreeBSD ports and Debian both
	carry it; Debian files it under "path-info" rather than as security.
	The CVE patches do not depend on it.

	doc/pkg-vulnerabilities gets four upper bounds moved to 2.29nb1.
	Three of them are open-ended today, so audit-packages reports
	thttpd whatever is installed:

	  thttpd-[0-9]*   -> thttpd<2.29nb1   CVE-2009-4491
	  thttpd-[0-9]*   -> thttpd<2.29nb1   CVE-2012-5640
	  thttpd-[0-9]*   -> thttpd<2.29nb1   CVE-2007-0158
	  thttpd<2.25bnb4 -> thttpd<2.29nb1   CVE-2005-3124

	The last one moves because the fix it refers to did not work.  Its
	URL also changes from the Secunia advisory, which no longer
	resolves, to the CVE entry.

	The Makefile gains LICENSE (28 files in the distfile carry the
	two-clause notice and none carries the "Neither the name" clause),
	two CFLAGS lines, and a rationale for MAKE_JOBS_SAFE:
	cgi-src/Makefile.in builds strerror.o by running make in the parent
	directory, and the top Makefile runs "all: this subdirs", so with -j
	the parent's build and the subdirectory's can compile that object
	into the same file at once.  The CFLAGS lines are there because
	glibc declares sigset(3) only under _XOPEN_SOURCE and illumos
	declares crypt(3c) only under __EXTENSIONS__; configure links
	against both and defines HAVE_SIGSET and HAVE_CRYPT, and gcc 14 then
	refuses a call with no prototype in scope.  Without them the package
	does not build on Debian 13 or on OmniOS.

	MESSAGE moves to files/README.pkgsrc, installed in share/doc/thttpd.
	The guide says MESSAGE is for cases where lasting harm follows from
	someone not reading it, and that configuration notes belong with the
	package's documentation.  The note is about making makeweb
	set-group-id, which is the administrator's decision.

	The rest of the Makefile is tidied to what pkglint wants: bsd.prefs.mk
	before the "?=", DIST_SUBDIR and SITES.* in their places, and the
	sed/mv in pre-configure moved into SUBST classes.  The renaming of
	htpasswd to thtpasswd stays a shell command, in post-patch, because
	it has to happen after the patches (which still name
	extras/htpasswd.c) and before the substitution.

	Measured on eight machines, each with its own pkgsrc bootstrap:
	NetBSD 10.1, FreeBSD 14.4, OpenBSD 7.9, DragonFly, OmniOS r151058,
	Debian 13 on x86_64 and aarch64, and Alpine.  Each run fetches
	pkgsrc-current and builds and installs the package from source.

	On each machine the unpatched 2.29 was built alongside and both were
	driven with real requests.  Where the 2002 configure stops the
	unpatched build -- the Linux machines and OmniOS -- the control was
	built with patch-configure alone, which writes the return type on
	the test programs' main() and touches none of thttpd's own code.

	  CVE-2012-5640  stock dies, patched answers 401
	                 all eight
	  CVE-2009-4491  stock writes the raw ESC, patched writes \x1b
	                 all eight
	  CVE-2005-3124  the installed syslogtocern parses and converts a
	                 syslog file; putting the second backtick back makes
	                 it stop parsing again
	                 all eight
	  CVE-2007-0158  stock reports the out-of-bounds read under ASan,
	                 patched is clean
	                 NetBSD and FreeBSD by both routes, the three Linux
	                 machines by the .htpasswd one

	The underflow is driven two ways because no single one reaches every
	machine: a zero-length symlink in the served tree, which Linux
	cannot create, and a .htpasswd line beginning with a NUL byte, which
	any of them can.  The first lands in expand_symlinks() and the
	second in auth_check2(), so between them the two guarded sites in
	libhttpd.c are both exercised.  On NetBSD the sanitizer will not
	start while ASLR is on; paxctl +a on the test binary is enough.

	The pkg-vulnerabilities change was checked by taking the published
	file, applying the same four edits, and running pkg_admin audit-pkg
	against thttpd-2.29nb1: three entries before, none after, on all
	eight.

	Not run: the underflow on OpenBSD, DragonFly and OmniOS.  There is
	no sanitizer to observe the read with, and I could not put one
	there:

	  OpenBSD    cc: error: unsupported option '-fsanitize=address'
	             for target 'amd64-unknown-openbsd7.9'
	  DragonFly  cannot find -lasan -- the base compiler takes the
	             option but has no runtime, and the dports gcc14 has
	             none either
	  OmniOS     gcc: error: -fsanitize=address is not supported in
	             this configuration -- both gcc13 and gcc14 are built
	             with libsanitizer off

	The patched package is built, installed and run on all three, and
	the other three CVEs are exercised there.  The two guarded sites
	are reached on five machines across three operating systems and two
	architectures, so no line of the patch is unexercised.

	The distfile matches distinfo, and all thirteen patches apply to it
	in order with no fuzz.

	pkglint 23.21.1 goes from 8 errors and 4 warnings to none.
Index: www/thttpd/Makefile
===================================================================
RCS file: /cvsroot/pkgsrc/www/thttpd/Makefile,v
retrieving revision 1.54
diff -u -r1.54 Makefile
--- www/thttpd/Makefile
+++ www/thttpd/Makefile
@@ -1,63 +1,96 @@
 # $NetBSD: Makefile,v 1.54 2025/03/30 10:02:53 nia Exp $
 
-DISTNAME=	thttpd-2.29
-CATEGORIES=	www
-MASTER_SITES=	https://www.acme.com/software/thttpd/
-DISTFILES=	${DISTNAME}${EXTRACT_SUFX} \
-		${NETBSD_LOGO}
-DIST_SUBDIR=	${PKGNAME_NOREV}
+DISTNAME=		thttpd-2.29
+PKGREVISION=		1
+CATEGORIES=		www
+MASTER_SITES=		https://www.acme.com/software/thttpd/
+DIST_SUBDIR=		${PKGNAME_NOREV}
+DISTFILES=		${DISTNAME}${EXTRACT_SUFX} ${NETBSD_LOGO}
+EXTRACT_ONLY=		${DISTNAME}${EXTRACT_SUFX}
+NETBSD_LOGO=		sitedrivenby.gif
+SITES.${NETBSD_LOGO}=	http://www.NetBSD.org/images/logos/
 
 MAINTAINER=	pkgsrc-users%NetBSD.org@localhost
 HOMEPAGE=	https://www.acme.com/software/thttpd/
 COMMENT=	Tiny/turbo/throttling HTTP server
+LICENSE=	2-clause-bsd
 
-EXTRACT_ONLY=	${DISTNAME}${EXTRACT_SUFX}
+GNU_CONFIGURE=	yes
 
-NETBSD_LOGO=		sitedrivenby.gif
-SITES.${NETBSD_LOGO}=	http://www.NetBSD.org/images/logos/
+# cgi-src/Makefile.in builds strerror.o by running make in the parent
+# directory ("cd .. ; $(MAKE) strerror.o"), and the top Makefile runs
+# "all: this subdirs", so with -j the parent's own build and the
+# subdirectory's can compile that object into the same file at once.
+MAKE_JOBS_SAFE=	no
 
-GNU_CONFIGURE=	yes
+.include "../../mk/bsd.prefs.mk"
 
 # Note: this pkg auto-detects IPv6.
-BUILD_DEFS+=		IPV6_READY
-# thttpd syslogs at level LOG_DAEMON by default
-# change this to your preferred syslog level
+BUILD_DEFS+=	IPV6_READY
+
+# thttpd syslogs at level LOG_DAEMON by default; change this to your
+# preferred syslog level.
 THTTPD_LOG_FACILITY?=	LOG_DAEMON
 BUILD_DEFS+=		THTTPD_LOG_FACILITY
 
+# glibc declares sigset(3) only under _XOPEN_SOURCE.  configure finds the
+# symbol anyway (it links), so HAVE_SIGSET is defined and thttpd.c calls it
+# with no prototype in scope -- an error with gcc 14 and later, where C23
+# made implicit declarations fatal.
+CFLAGS.Linux+=	-D_GNU_SOURCE
+
+# illumos declares crypt(3c) in <unistd.h> only under __EXTENSIONS__, and
+# thttpd includes no <crypt.h>.  Same failure mode as the Linux case above:
+# configure links against libc and sets HAVE_CRYPT, then gcc 14 refuses the
+# implicit declaration.
+CFLAGS.SunOS+=	-D__EXTENSIONS__
+
+CFLAGS.SCO_SV+=	-DMAXPATHLEN=255 -DS_IFSOCK=0
+
 EGDIR=		${PREFIX}/share/examples
+DOCDIR=		${PREFIX}/share/doc/thttpd
+
 CONF_FILES=	${EGDIR}/thttpd.conf ${PKG_SYSCONFDIR}/thttpd.conf
 RCD_SCRIPTS=	thttpd
 
-INSTALLATION_DIRS=	${PKGMANDIR}/man1 share/thttpd ${EGDIR}
+INSTALLATION_DIRS=	${PKGMANDIR}/man1 share/thttpd ${EGDIR} ${DOCDIR}
 
 SUBST_CLASSES+=		paths
-SUBST_FILES.paths=	thttpd.conf
-SUBST_VARS.paths=	PREFIX
 SUBST_STAGE.paths=	pre-configure
+SUBST_FILES.paths=	thttpd.conf README.pkgsrc
+SUBST_VARS.paths=	PREFIX
 
-MAKE_JOBS_SAFE=	no
+# htpasswd(1) is a common name, so the package installs it as thtpasswd.
+# post-patch does the renaming: after the patches, which still name
+# extras/htpasswd.c, and before this substitution runs.
+SUBST_CLASSES+=			thtpasswd
+SUBST_STAGE.thtpasswd=		pre-configure
+SUBST_MESSAGE.thtpasswd=	Renaming htpasswd to thtpasswd.
+SUBST_FILES.thtpasswd=		thttpd.8 extras/Makefile.in extras/thtpasswd.c
+SUBST_SED.thtpasswd=		-e 's,\.htpasswd,@DOTHTPASSWD@,g'
+SUBST_SED.thtpasswd+=		-e 's,htpasswd,thtpasswd,g'
+SUBST_SED.thtpasswd+=		-e 's,@DOTHTPASSWD@,.htpasswd,g'
 
-CFLAGS.SCO_SV+=	-DMAXPATHLEN=255 -DS_IFSOCK=0
+SUBST_CLASSES+=		logfac
+SUBST_STAGE.logfac=	pre-configure
+SUBST_MESSAGE.logfac=	Setting the syslog facility.
+SUBST_FILES.logfac=	config.h
+SUBST_SED.logfac=	-e 's,LOG_DAEMON,${THTTPD_LOG_FACILITY},'
 
 post-extract:
 	${CP} ${FILESDIR}/thttpd.conf ${WRKSRC}
+	${CP} ${FILESDIR}/README.pkgsrc ${WRKSRC}
 
-pre-configure:
+post-patch:
 	${MV} ${WRKSRC}/extras/htpasswd.1 ${WRKSRC}/extras/thtpasswd.1
 	${MV} ${WRKSRC}/extras/htpasswd.c ${WRKSRC}/extras/thtpasswd.c
-	for FILE in thttpd.8 extras/Makefile.in extras/thtpasswd.c; do	\
-		${MV} -f ${WRKSRC}/$${FILE} ${WRKSRC}/$${FILE}.bak;	\
-		${SED}	-e "s,\.htpasswd,XXX,g;s,htpasswd,thtpasswd,g;s,XXX,.htpasswd,g" \
-			${WRKSRC}/$${FILE}.bak > ${WRKSRC}/$${FILE};	\
-	done
-	${MV} -f ${WRKSRC}/config.h ${WRKSRC}/config.h.bak
-	${SED} -e "s/LOG_DAEMON/${THTTPD_LOG_FACILITY}/" ${WRKSRC}/config.h.bak \
-			> ${WRKSRC}/config.h
 
 post-install:
-	${INSTALL_DATA} ${WRKSRC}/thttpd.conf ${DESTDIR}${PREFIX}/share/examples
-	${INSTALL_DATA} ${WRKSRC}/index.html ${DESTDIR}${PREFIX}/share/thttpd
-	${INSTALL_DATA} ${DISTDIR}/${DIST_SUBDIR}/sitedrivenby.gif ${DESTDIR}${PREFIX}/share/thttpd
+	${INSTALL_DATA} ${WRKSRC}/README.pkgsrc ${DESTDIR}${DOCDIR}
+	${INSTALL_DATA} ${WRKSRC}/thttpd.conf ${DESTDIR}${EGDIR}
+	${INSTALL_DATA} ${WRKSRC}/index.html \
+		${DESTDIR}${PREFIX}/share/thttpd
+	${INSTALL_DATA} ${DISTDIR}/${DIST_SUBDIR}/${NETBSD_LOGO} \
+		${DESTDIR}${PREFIX}/share/thttpd
 
 .include "../../mk/bsd.pkg.mk"
Index: www/thttpd/distinfo
===================================================================
RCS file: /cvsroot/pkgsrc/www/thttpd/distinfo,v
retrieving revision 1.21
diff -u -r1.21 distinfo
--- www/thttpd/distinfo
+++ www/thttpd/distinfo
@@ -6,9 +6,16 @@
 BLAKE2s (thttpd-2.29/thttpd-2.29.tar.gz) = 023ee26357ec155995627c937e282ce5077dd1413f1f69f2f5927c883b2dca98
 SHA512 (thttpd-2.29/thttpd-2.29.tar.gz) = e02ed5b889eb3c875d56503093777c542316165a8df2d83e539337fb0759b6d9728fd484123dd903af57b06c97fe339055b816cca64778b7369b94020bd61ab6
 Size (thttpd-2.29/thttpd-2.29.tar.gz) = 133967 bytes
-SHA1 (patch-aa) = 0f739bebf1ade45a9b9819fc92d48eeb1004eb66
-SHA1 (patch-ab) = c6d6a20a00b4ceaf409b849982b8e963debf9530
-SHA1 (patch-ac) = f7fe1fed88b4cb33c9456d6fdc13e2bbc175ced6
-SHA1 (patch-ad) = 234127aaf4a3b5e6536bd08cc80f823800240fac
-SHA1 (patch-af) = 5160b635cdf9b3c997e93e039ef2764f77857018
-SHA1 (patch-ag) = 01410f8d293e2d4033f2a1119b21c05e21dfefbe
+SHA1 (patch-CVE-2005-3124) = af34d681b00af143ea86b696ae52b8b19fb619f7
+SHA1 (patch-CVE-2007-0158) = 49428634a39e4bda2f1d0a0a15cc62450c1259d1
+SHA1 (patch-CVE-2009-4491) = 37fa7858d14c7afff9d22ed1aa423b10cfe80516
+SHA1 (patch-CVE-2012-5640) = dda5e5a3e3b40e9d2997952f729e44d2d0ef58d1
+SHA1 (patch-Makefile.in) = 4c5b92df9e28d14ff83d00a4d951efa4595532ac
+SHA1 (patch-cgi-src_Makefile.in) = b80257756fcbb769b6540440b476f7548a5f117d
+SHA1 (patch-configure) = c3a09ec45abbfed2dced7e861333cf4376af2fbb
+SHA1 (patch-extras_Makefile.in) = c0c0df11f5ca945ef588d47a17906ad2d1c6c86c
+SHA1 (patch-extras_htpasswd.c) = 5cd23587d0a6d483462866c96fce5f2d31754556
+SHA1 (patch-index.html) = 2a7b22d91f8ef8cad7eecabdd8cb76fb44076b3e
+SHA1 (patch-libhttpd.c) = 89660ecceb2c4e3242c38a78f734db854d028f31
+SHA1 (patch-mmc.c) = 4052750ad1318f1d6776087f743a15ff609aed8c
+SHA1 (patch-thttpd.c) = 77e8de4f058ef27dc9463614e0c14295f0460fcb
Index: www/thttpd/PLIST
===================================================================
RCS file: /cvsroot/pkgsrc/www/thttpd/PLIST,v
retrieving revision 1.6
diff -u -r1.6 PLIST
--- www/thttpd/PLIST
+++ www/thttpd/PLIST
@@ -12,6 +12,7 @@
 sbin/syslogtocern
 sbin/thtpasswd
 sbin/thttpd
+share/doc/thttpd/README.pkgsrc
 share/examples/thttpd.conf
 share/thttpd/index.html
 share/thttpd/sitedrivenby.gif
Index: www/thttpd/patches/patch-CVE-2005-3124
===================================================================
RCS file: www/thttpd/patches/patch-CVE-2005-3124
diff -N www/thttpd/patches/patch-CVE-2005-3124
--- /dev/null
+++ www/thttpd/patches/patch-CVE-2005-3124
@@ -0,0 +1,34 @@
+$NetBSD$
+
+CVE-2005-3124 -- the script wrote to /tmp/stc1.$$, a name that can be
+worked out in advance, so anyone with write access to /tmp could put a
+symlink there and have the script write through it.  Use mktemp(1) and
+remove the file on the way out.  NVD says this was fixed before 2.23,
+but 2.29 still has the /tmp name, which is why the patch is still here.
+
+The line as written carried a stray second backtick, so the script it
+produced did not parse -- "sh -n" reports an unmatched backtick, and
+running it gives
+
+  syslogtocern: 34: Syntax error: "||" unexpected
+
+before it does anything.  That has been so since the patch was added in
+2005, so the installed syslogtocern has never run.  Nobody was exposed
+to the symlink attack by it, because a script that does not parse does
+not write anywhere; the tool was simply dead.  With the backtick removed
+it parses, keeps the mktemp(1) protection, and converts a syslog file
+into CERN-format access_log and error_log as the manual page says.
+
+--- extras/syslogtocern.orig	2005-05-20 19:10:25.000000000 +0000
++++ extras/syslogtocern
+@@ -31,8 +31,8 @@
+     exit 1
+ fi
+ 
+-tmp1=/tmp/stc1.$$
+-rm -f $tmp1
++tmp1=`mktemp -t stc1.XXXXXX` || { echo "$0: Cannot create temporary file" >&2; exit 1;  }
++trap " [ -f \"$tmp1\" ] && /bin/rm -f -- \"$tmp1\"" 0 1 2 3 13 15
+ 
+ # Gather up all the thttpd entries.
+ egrep -h ' thttpd\[' "$@" > $tmp1
Index: www/thttpd/patches/patch-CVE-2007-0158
===================================================================
RCS file: www/thttpd/patches/patch-CVE-2007-0158
diff -N www/thttpd/patches/patch-CVE-2007-0158
--- /dev/null
+++ www/thttpd/patches/patch-CVE-2007-0158
@@ -0,0 +1,112 @@
+$NetBSD$
+
+CVE-2007-0158 -- buffer underflow.  Five places index with length-1
+without checking the length.  Three are in expand_symlinks():
+
+  - with no_symlink_check (chroot mode) and a path of only slashes, the
+    trailing-slash trim drives checkedlen to 0 and then reads
+    checked[-1]; stat("/") always succeeds, so "/" reaches it;
+  - with an empty path, rest[restlen-1] reads before the buffer;
+  - with a zero-length symlink target in the served tree, readlink()
+    returns 0 and lnk[linklen-1] reads before the stack buffer.
+
+The fourth is in auth_check2(): fgets() returns non-NULL for a line that
+begins with a NUL byte, strlen() is then 0, and line[l-1] reads before
+the 500-byte stack buffer.  The .htpasswd is user-written, so this is
+reached the same way CVE-2012-5640 is, by requesting a protected
+directory.
+
+The fifth is in thttpd.c: max_connects is fdwatch_get_nfiles() minus
+SPARE_FDS, with no lower bound, so a file descriptor limit of 10 leaves
+it at 0.  connects[max_connects-1].next_free_connect is then written
+before the array; malloc(0) returns a pointer, so the allocation does
+not fail first.  With that limit thttpd starts and then refuses every
+connection (measured: HTTP 200 normally, no answer at all under
+"ulimit -n 10"), which is what max_connects <= 0 looks like from
+outside.  It now exits with a message instead.
+
+The four in libhttpd.c fire under AddressSanitizer on the routines
+extracted unchanged from 2.29, and are clean once guarded.
+
+What other packaging carries, for comparison:
+
+  site                    checkedlen  restlen  readlink  auth_check2
+  FreeBSD ports               yes       yes       no         no
+  Debian (2.25b-11)            no       yes*      no         no
+  ACME 2.30 (unreleased)        -         -      yes          -
+
+  * Debian drops the trailing-slash trim entirely rather than guarding it.
+
+(FreeBSD and Debian also change the PATH_INFO trimming near
+origfilename[i-1].  That one is not a length-1 underflow -- the stock
+"i > 0" test already prevents it -- it is a behaviour change, and it is
+kept separate in patch-libhttpd.c.)
+
+ACME's 2.30 changelog lists "off-by-one illegal memory access in
+expand_symlinks()", which is the readlink() case.
+
+--- libhttpd.c.orig
++++ libhttpd.c
+@@ -1117,9 +1117,11 @@
+     /* Read it. */
+     while ( fgets( line, sizeof(line), fp ) != (char*) 0 )
+ 	{
+-	/* Nuke newline. */
++	/* Nuke newline.  A NUL byte in the file leaves strlen() at 0, and
++	** line[l-1] would then read before the buffer.
++	*/
+ 	l = strlen( line );
+-	if ( line[l - 1] == '\n' )
++	if ( l > 0 && line[l - 1] == '\n' )
+ 	    line[l - 1] = '\0';
+ 	/* Split into user and encrypted password. */
+ 	cryp = strchr( line, ':' );
+@@ -1486,7 +1488,7 @@
+ 	    httpd_realloc_str( &checked, &maxchecked, checkedlen );
+ 	    (void) strcpy( checked, path );
+ 	    /* Trim trailing slashes. */
+-	    while ( checked[checkedlen - 1] == '/' )
++	    while ( checkedlen > 0 && checked[checkedlen - 1] == '/' )
+ 		{
+ 		checked[checkedlen - 1] = '\0';
+ 		--checkedlen;
+@@ -1505,7 +1507,7 @@
+     restlen = strlen( path );
+     httpd_realloc_str( &rest, &maxrest, restlen );
+     (void) strcpy( rest, path );
+-    if ( rest[restlen - 1] == '/' )
++    if ( restlen > 0 && rest[restlen - 1] == '/' )
+ 	rest[--restlen] = '\0';         /* trim trailing slash */
+     if ( ! tildemapped )
+ 	/* Remove any leading slashes. */
+@@ -1623,7 +1625,9 @@
+ 	    return (char*) 0;
+ 	    }
+ 	lnk[linklen] = '\0';
+-	if ( lnk[linklen - 1] == '/' )
++	/* An empty symlink target makes readlink() return 0, and
++	** lnk[linklen-1] then reads lnk[-1], underflowing the buffer. */
++	if ( linklen > 0 && lnk[linklen - 1] == '/' )
+ 	    lnk[--linklen] = '\0';     /* trim trailing slash */
+ 
+ 	/* Insert the link contents in front of the rest of the filename. */
+--- thttpd.c.orig
++++ thttpd.c
+@@ -554,6 +554,17 @@
+ 	exit( 1 );
+ 	}
+     max_connects -= SPARE_FDS;
++    if ( max_connects <= 0 )
++	{
++	/* With a file descriptor limit this low there is no room for even one
++	** connection, and connects[max_connects-1] below would write before
++	** the array.  malloc(0) returns a pointer, so this is not caught by
++	** the allocation failing.
++	*/
++	syslog( LOG_CRIT, "file descriptor limit is too low for any connection" );
++	(void) fprintf( stderr, "%s: file descriptor limit is too low for any connection\n", argv0 );
++	exit( 1 );
++	}
+ 
+     /* Chroot if requested. */
+     if ( do_chroot )
Index: www/thttpd/patches/patch-CVE-2009-4491
===================================================================
RCS file: www/thttpd/patches/patch-CVE-2009-4491
diff -N www/thttpd/patches/patch-CVE-2009-4491
--- /dev/null
+++ www/thttpd/patches/patch-CVE-2009-4491
@@ -0,0 +1,332 @@
+$NetBSD$
+
+CVE-2009-4491 -- log injection.  thttpd writes the request line, the
+headers and values derived from them to the log exactly as the client
+sent them, so a request can place terminal escape sequences into the
+log.  Control characters are written as \xHH instead.
+
+This is not only the access log.  Every one of these logs a value the
+client controls, and none of them sanitised it:
+
+  make_log_entry()  the access log and its syslog form: URL, Referer,
+                    User-Agent, remote user
+  the "unparsable time" pair  the raw If-Modified-Since and If-Range
+                    header values
+  check_referrer()  the Referer host, the URL and the Referer
+  thirteen more     the URL or the expanded filename, in the "goes
+                    outside the web tree", "tried to index a
+                    directory", "tried to retrieve an auth file",
+                    "isn't CGI", opendir, execve and spawn messages
+  thttpd.c          the URL in the write-error message
+
+httpd_log_escape() is exported because thttpd.c needs it too.  It hands
+back a pointer into a small ring of static buffers so that several
+values can be escaped in one syslog() call; thttpd is single-threaded,
+so that is safe.
+
+Not in ACME's 2.30 changelog, and not carried by FreeBSD ports, Debian,
+Fedora, Alpine, MacPorts or Void.
+
+--- libhttpd.c.orig
++++ libhttpd.c
+@@ -172,6 +172,7 @@
+ static int cgi( httpd_conn* hc );
+ static int really_start_request( httpd_conn* hc, struct timeval* nowP );
+ static void make_log_entry( httpd_conn* hc, struct timeval* nowP );
++static char* log_escape( char* dst, size_t dstsize, const char* src );
+ static int check_referrer( httpd_conn* hc );
+ static int really_check_referrer( httpd_conn* hc );
+ static int sockaddr_check( httpd_sockaddr* saP );
+@@ -1619,7 +1620,7 @@
+ 	++nlinks;
+ 	if ( nlinks > MAX_LINKS )
+ 	    {
+-	    syslog( LOG_ERR, "too many symlinks in %.80s", path );
++	    syslog( LOG_ERR, "too many symlinks in %.80s", httpd_log_escape( path ) );
+ 	    return (char*) 0;
+ 	    }
+ 	lnk[linklen] = '\0';
+@@ -2173,7 +2174,8 @@
+ 		cp = &buf[18];
+ 		hc->if_modified_since = tdate_parse( cp );
+ 		if ( hc->if_modified_since == (time_t) -1 )
+-		    syslog( LOG_DEBUG, "unparsable time: %.80s", cp );
++		    syslog( LOG_DEBUG, "unparsable time: %.80s",
++			httpd_log_escape( cp ) );
+ 		}
+ 	    else if ( strncasecmp( buf, "Cookie:", 7 ) == 0 )
+ 		{
+@@ -2214,7 +2216,8 @@
+ 		cp = &buf[9];
+ 		hc->range_if = tdate_parse( cp );
+ 		if ( hc->range_if == (time_t) -1 )
+-		    syslog( LOG_DEBUG, "unparsable time: %.80s", cp );
++		    syslog( LOG_DEBUG, "unparsable time: %.80s",
++			httpd_log_escape( cp ) );
+ 		}
+ 	    else if ( strncasecmp( buf, "Content-Type:", 13 ) == 0 )
+ 		{
+@@ -2380,7 +2383,7 @@
+ 	    {
+ 	    syslog(
+ 		LOG_NOTICE, "%.80s URL \"%.80s\" goes outside the web tree",
+-		httpd_ntoa( &hc->client_addr ), hc->encodedurl );
++		httpd_ntoa( &hc->client_addr ), httpd_log_escape( hc->encodedurl ) );
+ 	    httpd_send_err(
+ 		hc, 403, err403title, "",
+ 		ERROR_FORM( err403form, "The requested URL '%.80s' resolves to a file outside the permitted web server directory tree.\n" ),
+@@ -2734,7 +2737,7 @@
+     dirp = opendir( hc->expnfilename );
+     if ( dirp == (DIR*) 0 )
+ 	{
+-	syslog( LOG_ERR, "opendir %.80s - %m", hc->expnfilename );
++	syslog( LOG_ERR, "opendir %.80s - %m", httpd_log_escape( hc->expnfilename ) );
+ 	httpd_send_err( hc, 404, err404title, "", err404form, hc->encodedurl );
+ 	return -1;
+ 	}
+@@ -2974,7 +2977,8 @@
+ 
+ 	/* Parent process. */
+ 	closedir( dirp );
+-	syslog( LOG_DEBUG, "spawned indexing process %d for directory '%.200s'", r, hc->expnfilename );
++	syslog( LOG_DEBUG, "spawned indexing process %d for directory '%.200s'",
++	    r, httpd_log_escape( hc->expnfilename ) );
+ #ifdef CGI_TIMELIMIT
+ 	/* Schedule a kill for the child process, in case it runs too long */
+ 	client_data.i = r;
+@@ -3563,7 +3567,7 @@
+     (void) execve( binary, argp, envp );
+ 
+     /* Something went wrong. */
+-    syslog( LOG_ERR, "execve %.80s - %m", hc->expnfilename );
++    syslog( LOG_ERR, "execve %.80s - %m", httpd_log_escape( hc->expnfilename ) );
+     httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl );
+     httpd_write_response( hc );
+     _exit( 1 );
+@@ -3602,7 +3606,8 @@
+ 	}
+ 
+     /* Parent process. */
+-    syslog( LOG_DEBUG, "spawned CGI process %d for file '%.200s'", r, hc->expnfilename );
++    syslog( LOG_DEBUG, "spawned CGI process %d for file '%.200s'",
++	    r, httpd_log_escape( hc->expnfilename ) );
+ #ifdef CGI_TIMELIMIT
+     /* Schedule a kill for the child process, in case it runs too long */
+     client_data.i = r;
+@@ -3654,7 +3659,7 @@
+ 	syslog(
+ 	    LOG_INFO,
+ 	    "%.80s URL \"%.80s\" resolves to a non world-readable file",
+-	    httpd_ntoa( &hc->client_addr ), hc->encodedurl );
++	    httpd_ntoa( &hc->client_addr ), httpd_log_escape( hc->encodedurl ) );
+ 	httpd_send_err(
+ 	    hc, 403, err403title, "",
+ 	    ERROR_FORM( err403form, "The requested URL '%.80s' resolves to a file that is not world-readable.\n" ),
+@@ -3709,7 +3714,7 @@
+ 	    syslog(
+ 		LOG_INFO,
+ 		"%.80s URL \"%.80s\" tried to index a directory with indexing disabled",
+-		httpd_ntoa( &hc->client_addr ), hc->encodedurl );
++		httpd_ntoa( &hc->client_addr ), httpd_log_escape( hc->encodedurl ) );
+ 	    httpd_send_err(
+ 		hc, 403, err403title, "",
+ 		ERROR_FORM( err403form, "The requested URL '%.80s' resolves to a directory that has indexing disabled.\n" ),
+@@ -3729,7 +3734,7 @@
+ #else /* GENERATE_INDEXES */
+ 	syslog(
+ 	    LOG_INFO, "%.80s URL \"%.80s\" tried to index a directory",
+-	    httpd_ntoa( &hc->client_addr ), hc->encodedurl );
++	    httpd_ntoa( &hc->client_addr ), httpd_log_escape( hc->encodedurl ) );
+ 	httpd_send_err(
+ 	    hc, 403, err403title, "",
+ 	    ERROR_FORM( err403form, "The requested URL '%.80s' is a directory, and directory indexing is disabled on this server.\n" ),
+@@ -3757,7 +3762,7 @@
+ 	    syslog(
+ 		LOG_INFO,
+ 		"%.80s URL \"%.80s\" resolves to a non-world-readable index file",
+-		httpd_ntoa( &hc->client_addr ), hc->encodedurl );
++		httpd_ntoa( &hc->client_addr ), httpd_log_escape( hc->encodedurl ) );
+ 	    httpd_send_err(
+ 		hc, 403, err403title, "",
+ 		ERROR_FORM( err403form, "The requested URL '%.80s' resolves to an index file that is not world-readable.\n" ),
+@@ -3786,7 +3791,7 @@
+ 	    syslog(
+ 		LOG_NOTICE,
+ 		"%.80s URL \"%.80s\" tried to retrieve an auth file",
+-		httpd_ntoa( &hc->client_addr ), hc->encodedurl );
++		httpd_ntoa( &hc->client_addr ), httpd_log_escape( hc->encodedurl ) );
+ 	    httpd_send_err(
+ 		hc, 403, err403title, "",
+ 		ERROR_FORM( err403form, "The requested URL '%.80s' is an authorization file, retrieving it is not permitted.\n" ),
+@@ -3801,7 +3806,7 @@
+ 	syslog(
+ 	    LOG_NOTICE,
+ 	    "%.80s URL \"%.80s\" tried to retrieve an auth file",
+-	    httpd_ntoa( &hc->client_addr ), hc->encodedurl );
++	    httpd_ntoa( &hc->client_addr ), httpd_log_escape( hc->encodedurl ) );
+ 	httpd_send_err(
+ 	    hc, 403, err403title, "",
+ 	    ERROR_FORM( err403form, "The requested URL '%.80s' is an authorization file, retrieving it is not permitted.\n" ),
+@@ -3828,7 +3833,7 @@
+ 	{
+ 	syslog(
+ 	    LOG_NOTICE, "%.80s URL \"%.80s\" is executable but isn't CGI",
+-	    httpd_ntoa( &hc->client_addr ), hc->encodedurl );
++	    httpd_ntoa( &hc->client_addr ), httpd_log_escape( hc->encodedurl ) );
+ 	httpd_send_err(
+ 	    hc, 403, err403title, "",
+ 	    ERROR_FORM( err403form, "The requested URL '%.80s' resolves to a file which is marked executable but is not a CGI file; retrieving it is forbidden.\n" ),
+@@ -3839,7 +3844,7 @@
+ 	{
+ 	syslog(
+ 	    LOG_INFO, "%.80s URL \"%.80s\" has pathinfo but isn't CGI",
+-	    httpd_ntoa( &hc->client_addr ), hc->encodedurl );
++	    httpd_ntoa( &hc->client_addr ), httpd_log_escape( hc->encodedurl ) );
+ 	httpd_send_err(
+ 	    hc, 403, err403title, "",
+ 	    ERROR_FORM( err403form, "The requested URL '%.80s' resolves to a file plus CGI-style pathinfo, but the file is not a valid CGI file.\n" ),
+@@ -3904,12 +3909,65 @@
+     }
+ 
+ 
++/* Copy src into dst, replacing control characters with \xHH.  The request
++** line, the headers and anything derived from them reach the log exactly as
++** the client sent them, so without this a request can write terminal escape
++** sequences into the log.
++*/
++static char*
++log_escape( char* dst, size_t dstsize, const char* src )
++    {
++    static const char hex[] = "0123456789abcdef";
++    size_t i = 0;
++    unsigned char c;
++
++    if ( src == (const char*) 0 )
++	src = "";
++    for ( ; *src != '\0' && i + 4 < dstsize; ++src )
++	{
++	c = (unsigned char) *src;
++	if ( c < 0x20 || c == 0x7f )
++	    {
++	    dst[i++] = '\\';
++	    dst[i++] = 'x';
++	    dst[i++] = hex[c >> 4];
++	    dst[i++] = hex[c & 0xf];
++	    }
++	else
++	    dst[i++] = c;
++	}
++    dst[i] = '\0';
++    return dst;
++    }
++
++
++/* The same, for use straight in a syslog() argument list.  Returns a pointer
++** into a small ring of buffers so that more than one value can be escaped in
++** one call.  thttpd is single-threaded, so this is safe.
++*/
++char*
++httpd_log_escape( const char* src )
++    {
++    static char bufs[4][1000];
++    static int next = 0;
++    char* dst;
++
++    dst = bufs[next];
++    next = ( next + 1 ) % 4;
++    return log_escape( dst, sizeof(bufs[0]), src );
++    }
++
++
+ static void
+ make_log_entry( httpd_conn* hc, struct timeval* nowP )
+     {
+     char* ru;
+     char url[305];
+     char bytes[40];
++    char eurl[305 * 4];
++    char eref[200 * 4 + 1];
++    char eua[200 * 4 + 1];
++    char eru[80 * 4 + 1];
+ 
+     if ( hc->hs->no_log )
+ 	return;
+@@ -3922,7 +3980,7 @@
+ 
+     /* Format remote user. */
+     if ( hc->remoteuser[0] != '\0' )
+-	ru = hc->remoteuser;
++	ru = log_escape( eru, sizeof(eru), hc->remoteuser );
+     else
+ 	ru = "-";
+     /* If we're vhosting, prepend the hostname to the url.  This is
+@@ -3937,6 +3995,9 @@
+     else
+ 	(void) my_snprintf( url, sizeof(url),
+ 	    "%.200s", hc->encodedurl );
++    (void) log_escape( eurl, sizeof(eurl), url );
++    (void) log_escape( eref, sizeof(eref), hc->referrer );
++    (void) log_escape( eua, sizeof(eua), hc->useragent );
+     /* Format the bytes. */
+     if ( hc->bytes_sent >= 0 )
+ 	(void) my_snprintf(
+@@ -3985,8 +4046,8 @@
+ 	(void) fprintf( hc->hs->logfp,
+ 	    "%.80s - %.80s [%s] \"%.80s %.300s %.80s\" %d %s \"%.200s\" \"%.200s\"\n",
+ 	    httpd_ntoa( &hc->client_addr ), ru, date,
+-	    httpd_method_str( hc->method ), url, hc->protocol,
+-	    hc->status, bytes, hc->referrer, hc->useragent );
++	    httpd_method_str( hc->method ), eurl, hc->protocol,
++	    hc->status, bytes, eref, eua );
+ #ifdef FLUSH_LOG_EVERY_TIME
+ 	(void) fflush( hc->hs->logfp );
+ #endif
+@@ -3995,8 +4056,8 @@
+ 	syslog( LOG_INFO,
+ 	    "%.80s - %.80s \"%.80s %.200s %.80s\" %d %s \"%.200s\" \"%.200s\"",
+ 	    httpd_ntoa( &hc->client_addr ), ru,
+-	    httpd_method_str( hc->method ), url, hc->protocol,
+-	    hc->status, bytes, hc->referrer, hc->useragent );
++	    httpd_method_str( hc->method ), eurl, hc->protocol,
++	    hc->status, bytes, eref, eua );
+     }
+ 
+ 
+@@ -4023,7 +4084,9 @@
+ 	    cp = "";
+ 	syslog(
+ 	    LOG_INFO, "%.80s non-local referrer \"%.80s%.80s\" \"%.80s\"",
+-	    httpd_ntoa( &hc->client_addr ), cp, hc->encodedurl, hc->referrer );
++	    httpd_ntoa( &hc->client_addr ), httpd_log_escape( cp ),
++	    httpd_log_escape( hc->encodedurl ),
++	    httpd_log_escape( hc->referrer ) );
+ 	httpd_send_err(
+ 	    hc, 403, err403title, "",
+ 	    ERROR_FORM( err403form, "You must supply a local referrer to get URL '%.80s' from this server.\n" ),
+--- libhttpd.h.orig
++++ libhttpd.h
+@@ -263,6 +263,12 @@
+ extern char* httpd_err408form;
+ extern char* httpd_err503title;
+ extern char* httpd_err503form;
++
++/* Escape control characters in a string for the log, so that a request
++** cannot write terminal escape sequences into it.  Returns a pointer into
++** a small ring of static buffers.
++*/
++char* httpd_log_escape( const char* src );
+ 
+ /* Generate a string representation of a method number. */
+ char* httpd_method_str( int method );
+--- thttpd.c.orig
++++ thttpd.c
+@@ -1778,7 +1778,8 @@
+ 	** And ECONNRESET isn't interesting either.
+ 	*/
+ 	if ( errno != EPIPE && errno != EINVAL && errno != ECONNRESET )
+-	    syslog( LOG_ERR, "write - %m sending %.80s", hc->encodedurl );
++	    syslog( LOG_ERR, "write - %m sending %.80s",
++		httpd_log_escape( hc->encodedurl ) );
+ 	clear_connection( c, tvP );
+ 	return;
+ 	}
Index: www/thttpd/patches/patch-CVE-2012-5640
===================================================================
RCS file: www/thttpd/patches/patch-CVE-2012-5640
diff -N www/thttpd/patches/patch-CVE-2012-5640
--- /dev/null
+++ www/thttpd/patches/patch-CVE-2012-5640
@@ -0,0 +1,82 @@
+$NetBSD$
+
+CVE-2012-5640 -- denial of service.  crypt() returns NULL for a salt it
+does not recognise (glibc and illumos do; NetBSD and current Linux
+return "*0" instead).  thttpd passes the result straight on in all three
+places it calls crypt(), and the salt comes from a user-written
+.htpasswd, so one malformed line is enough.
+
+In auth_check2() the result is handed to strcmp(), so a request for the
+protected directory crashes the server.  Note that the fix must keep
+going to the send_authenticate() call below rather than returning
+straight away: this function documents -1 as "unauthorized" and every
+existing -1 is preceded by send_authenticate(), and the callers take -1
+to mean a response has already been written.  Returning -1 without it
+would answer the request with nothing at all.  Fedora and Alpine carry
+this fix in the shorter "return -1" form, which has that effect.  A
+syslog line is added because an unusable salt is an administrator's
+mistake, not a wrong password.
+
+In extras/htpasswd.c the result is passed to fprintf("%s"), so writing a
+password with a salt crypt() dislikes dereferences NULL.  Fedora and
+Alpine guard this one too.
+
+ACME lists a crypt() NULL check for the unreleased 2.30.
+
+--- libhttpd.c.orig
++++ libhttpd.c
+@@ -1030,6 +1030,7 @@
+     FILE* fp;
+     char line[500];
+     char* cryp;
++    char* cryp2;
+     static char* prevauthpath;
+     static size_t maxprevauthpath = 0;
+     static time_t prevmtime;
+@@ -1082,8 +1083,16 @@
+ 	 sb.st_mtime == prevmtime &&
+ 	 strcmp( authinfo, prevuser ) == 0 )
+ 	{
+-	/* Yes.  Check against the cached encrypted password. */
+-	if ( strcmp( crypt( authpass, prevcryp ), prevcryp ) == 0 )
++	/* Yes.  Check against the cached encrypted password.  crypt() returns
++	** NULL for a salt it does not understand, and the password file is
++	** user-supplied, so a bad line must not be dereferenced.  Treat it as
++	** a mismatch so that the send_authenticate() below still runs: the
++	** callers take -1 to mean a response has already been sent.
++	*/
++	cryp = crypt( authpass, prevcryp );
++	if ( cryp == (char*) 0 )
++	    syslog( LOG_ERR, "unusable password for %.80s in %.80s", authinfo, authpath );
++	if ( cryp != (char*) 0 && strcmp( cryp, prevcryp ) == 0 )
+ 	    {
+ 	    /* Ok! */
+ 	    httpd_realloc_str(
+@@ -1131,8 +1140,11 @@
+ 	    {
+ 	    /* Yes. */
+ 	    (void) fclose( fp );
+-	    /* So is the password right? */
+-	    if ( strcmp( crypt( authpass, cryp ), cryp ) == 0 )
++	    /* So is the password right?  As above, crypt() may return NULL. */
++	    cryp2 = crypt( authpass, cryp );
++	    if ( cryp2 == (char*) 0 )
++		syslog( LOG_ERR, "unusable password for %.80s in %.80s", line, authpath );
++	    if ( cryp2 != (char*) 0 && strcmp( cryp2, cryp ) == 0 )
+ 		{
+ 		/* Ok! */
+ 		httpd_realloc_str(
+--- extras/htpasswd.c.orig
++++ extras/htpasswd.c
+@@ -131,6 +131,11 @@
+     (void) srandom( (int) time( (time_t*) 0 ) );
+     to64( &salt[0], random(), 2 );
+     cpw = crypt( pw, salt );
++    if ( cpw == (char*) 0 )
++	{
++	(void) fprintf( stderr, "htpasswd: crypt() could not hash the password\n" );
++	exit( 1 );
++	}
+     (void) fprintf( f, "%s:%s\n", user, cpw );
+     }
+ 
Index: www/thttpd/patches/patch-Makefile.in
===================================================================
RCS file: www/thttpd/patches/patch-Makefile.in
diff -N www/thttpd/patches/patch-Makefile.in
--- /dev/null
+++ www/thttpd/patches/patch-Makefile.in
@@ -0,0 +1,59 @@
+$NetBSD$
+
+Install into the pkgsrc layout instead of the upstream defaults: the
+CGI programs go to libexec/cgi-bin and the sample web root to
+share/thttpd, rather than under $prefix/www.
+
+Use the BSD_INSTALL_* tools rather than "mkdir -p" and an install(1)
+run with a hardcoded owner of bin:bin, so that DESTDIR and the
+unprivileged build both work.
+
+CFLAGS is appended to rather than assigned, so that the flags pkgsrc
+passes in survive.
+
+--- Makefile.in.orig	2005-05-20 19:10:24.000000000 +0000
++++ Makefile.in
+@@ -34,7 +34,7 @@
+ # Pathname of directory to install the man page.
+ MANDIR = @mandir@
+ # Pathname of directory to install the CGI programs.
+-WEBDIR = $(prefix)/www
++WEBDIR = $(prefix)/share/thttpd
+ 
+ # CONFIGURE: The group that the web directory belongs to.  This is so that
+ # the makeweb program can be installed set-group-id to that group, and make
+@@ -42,7 +42,7 @@
+ WEBGROUP =	www
+ 
+ # CONFIGURE: Directory for CGI executables.
+-CGIBINDIR =	$(WEBDIR)/cgi-bin
++CGIBINDIR =	$(prefix)/libexec/cgi-bin
+ 
+ # You shouldn't need to edit anything below here.
+ 
+@@ -50,7 +50,7 @@
+ CCOPT =		@V_CCOPT@
+ DEFS =		@DEFS@
+ INCLS =		-I.
+-CFLAGS =	$(CCOPT) $(DEFS) $(INCLS)
++CFLAGS +=	$(CCOPT) $(DEFS) $(INCLS)
+ LDFLAGS =	@LDFLAGS@
+ LIBS =		@LIBS@
+ NETLIBS =	@V_NETLIBS@
+@@ -109,12 +109,12 @@
+ install:	installthis install-man installsubdirs
+ 
+ installthis:
+-	-mkdir -p $(DESTDIR)$(BINDIR)
+-	$(INSTALL) -m 555 -o bin -g bin thttpd $(DESTDIR)$(BINDIR)
++	$(BSD_INSTALL_PROGRAM_DIR) $(DESTDIR)$(BINDIR)
++	$(BSD_INSTALL_PROGRAM) thttpd $(DESTDIR)$(BINDIR)
+ 
+ install-man:
+-	-mkdir -p $(DESTDIR)$(MANDIR)/man8
+-	$(INSTALL) -m 444 -o bin -g bin thttpd.8 $(DESTDIR)$(MANDIR)/man8
++	$(BSD_INSTALL_DATA_DIR) $(DESTDIR)$(MANDIR)/man8
++	$(BSD_INSTALL_MAN) thttpd.8 $(DESTDIR)$(MANDIR)/man8
+ 
+ installsubdirs:
+ 	for i in $(SUBDIRS) ; do ( \
Index: www/thttpd/patches/patch-cgi-src_Makefile.in
===================================================================
RCS file: www/thttpd/patches/patch-cgi-src_Makefile.in
diff -N www/thttpd/patches/patch-cgi-src_Makefile.in
--- /dev/null
+++ www/thttpd/patches/patch-cgi-src_Makefile.in
@@ -0,0 +1,46 @@
+$NetBSD$
+
+The same as patch-ab for the CGI programs: honour DESTDIR, install with
+the BSD_INSTALL_* tools instead of cp, and append to CFLAGS rather than
+overwrite it.
+
+--- cgi-src/Makefile.in.orig	2005-05-20 19:10:25.000000000 +0000
++++ cgi-src/Makefile.in
+@@ -34,7 +34,7 @@
+ CCOPT =		@V_CCOPT@
+ DEFS =		@DEFS@
+ INCLS =		-I..
+-CFLAGS =	$(CCOPT) $(DEFS) $(INCLS)
++CFLAGS +=	$(CCOPT) $(DEFS) $(INCLS)
+ LDFLAGS =	@LDFLAGS@ @V_STATICFLAG@
+ LIBS =		@LIBS@
+ NETLIBS =	@V_NETLIBS@
+@@ -67,17 +67,17 @@
+ 	cd .. ; $(MAKE) $(MFLAGS) strerror.o
+ 
+ install:	all
+-	-mkdir -p $(CGIBINDIR)
+-	rm -f $(CGIBINDIR)/redirect
+-	cp redirect $(CGIBINDIR)/redirect
+-	rm -f $(MANDIR)/man8/redirect.8
+-	cp redirect.8 $(MANDIR)/man8/redirect.8
+-	rm -f $(CGIBINDIR)/ssi
+-	cp ssi $(CGIBINDIR)/ssi
+-	rm -f $(MANDIR)/man8/ssi.8
+-	cp ssi.8 $(MANDIR)/man8/ssi.8
+-	rm -f $(CGIBINDIR)/phf
+-	cp phf $(CGIBINDIR)/phf
++	-mkdir -p $(DESTDIR)$(CGIBINDIR)
++	rm -f $(DESTDIR)$(CGIBINDIR)/redirect
++	$(BSD_INSTALL_PROGRAM) redirect $(DESTDIR)$(CGIBINDIR)/redirect
++	rm -f $(DESTDIR)$(MANDIR)/man8/redirect.8
++	$(BSD_INSTALL_MAN) redirect.8 $(DESTDIR)$(MANDIR)/man8/redirect.8
++	rm -f $(DESTDIR)$(CGIBINDIR)/ssi
++	$(BSD_INSTALL_PROGRAM) ssi $(DESTDIR)$(CGIBINDIR)/ssi
++	rm -f $(DESTDIR)$(MANDIR)/man8/ssi.8
++	$(BSD_INSTALL_MAN) ssi.8 $(DESTDIR)$(MANDIR)/man8/ssi.8
++	rm -f $(DESTDIR)$(CGIBINDIR)/phf
++	$(BSD_INSTALL_PROGRAM) phf $(DESTDIR)$(CGIBINDIR)/phf
+ 
+ clean:
+ 	rm -f $(CLEANFILES)
Index: www/thttpd/patches/patch-configure
===================================================================
RCS file: www/thttpd/patches/patch-configure
diff -N www/thttpd/patches/patch-configure
--- /dev/null
+++ www/thttpd/patches/patch-configure
@@ -0,0 +1,49 @@
+$NetBSD$
+
+Not a CVE: the configure script's test programs declare main() without a
+return type.  C99 removed implicit int and current compilers reject it,
+so the very first test -- "checking whether the C compiler works" --
+fails and configure stops with "C compiler cannot create executables".
+gcc 14 and clang 16 and later are in that state; this was measured with
+clang 21 and it is what breaks the build on Debian 13.
+
+Fedora and MacPorts both carry this fix.
+
+--- configure.orig
++++ configure
+@@ -761,7 +761,7 @@
+ #line 762 "configure"
+ #include "confdefs.h"
+ 
+-main(){return(0);}
++int main(){return(0);}
+ EOF
+ if { (eval echo configure:767: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+   ac_cv_prog_cc_works=yes
+@@ -880,7 +880,7 @@
+   echo $ac_n "(cached) $ac_c" 1>&6
+ else
+   ac_cv_lbl_static_flag=unknown
+-    echo 'main() {}' > conftest.c
++    echo 'int main() {}' > conftest.c
+     if test "$GCC" != yes ; then
+ 	    trial_flag="-Bstatic"
+ 	    test=`$CC $trial_flag -o conftest conftest.c 2>&1`
+@@ -1588,7 +1588,7 @@
+ #include "confdefs.h"
+ 
+ int main() {
+-main()
++int main()
+ ; return 0; }
+ EOF
+ if { (eval echo configure:1595: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+@@ -2095,7 +2095,7 @@
+ #endif
+ 
+ int
+-main()
++int main()
+ {
+ 	char *data, *data2, *data3;
+ 	int i, pagesize;
Index: www/thttpd/patches/patch-extras_Makefile.in
===================================================================
RCS file: www/thttpd/patches/patch-extras_Makefile.in
diff -N www/thttpd/patches/patch-extras_Makefile.in
--- /dev/null
+++ www/thttpd/patches/patch-extras_Makefile.in
@@ -0,0 +1,51 @@
+$NetBSD$
+
+The same two things as patch-aa, for the helper programs: honour
+DESTDIR, install with the BSD_INSTALL_* tools instead of cp, and append
+to CFLAGS rather than overwrite it.
+
+syslogtocern is a shell script, so it goes in with BSD_INSTALL_SCRIPT.
+
+The upstream rule also made makeweb set-group-id here; that is left to
+the administrator instead, which is what README.pkgsrc explains.
+
+--- extras/Makefile.in.orig	2005-05-20 19:10:25.000000000 +0000
++++ extras/Makefile.in
+@@ -35,7 +35,7 @@
+ CCOPT =		@V_CCOPT@
+ DEFS =		@DEFS@
+ INCLS =		-I..
+-CFLAGS =	$(CCOPT) $(DEFS) $(INCLS)
++CFLAGS +=	$(CCOPT) $(DEFS) $(INCLS)
+ STATICFLAG =	@V_STATICFLAG@
+ LDFLAGS =	@LDFLAGS@
+ LIBS =		@LIBS@
+@@ -66,18 +66,16 @@
+ 
+ 
+ install:	all
+-	rm -f $(BINDIR)/makeweb $(BINDIR)/htpasswd $(BINDIR)/syslogtocern
+-	cp makeweb $(BINDIR)/makeweb
+-	chgrp $(WEBGROUP) $(BINDIR)/makeweb
+-	chmod 2755 $(BINDIR)/makeweb
+-	cp htpasswd $(BINDIR)/htpasswd
+-	cp syslogtocern $(BINDIR)/syslogtocern
+-	rm -f $(MANDIR)/man1/makeweb.1
+-	cp makeweb.1 $(MANDIR)/man1/makeweb.1
+-	rm -f $(MANDIR)/man1/htpasswd.1
+-	cp htpasswd.1 $(MANDIR)/man1/htpasswd.1
+-	rm -f $(MANDIR)/man8/syslogtocern.8
+-	cp syslogtocern.8 $(MANDIR)/man8/syslogtocern.8
++	rm -f $(DESTDIR)$(BINDIR)/makeweb $(DESTDIR)$(BINDIR)/htpasswd $(DESTDIR)$(BINDIR)/syslogtocern
++	$(BSD_INSTALL_PROGRAM) makeweb $(DESTDIR)$(BINDIR)/makeweb
++	$(BSD_INSTALL_PROGRAM) htpasswd $(DESTDIR)$(BINDIR)/htpasswd
++	$(BSD_INSTALL_SCRIPT) syslogtocern $(DESTDIR)$(BINDIR)/syslogtocern
++	rm -f $(DESTDIR)$(MANDIR)/man1/makeweb.1
++	$(BSD_INSTALL_MAN) makeweb.1 $(DESTDIR)$(MANDIR)/man1/makeweb.1
++	rm -f $(DESTDIR)$(MANDIR)/man1/htpasswd.1
++	$(BSD_INSTALL_MAN) htpasswd.1 $(DESTDIR)$(MANDIR)/man1/htpasswd.1
++	rm -f $(DESTDIR)$(MANDIR)/man8/syslogtocern.8
++	$(BSD_INSTALL_MAN) syslogtocern.8 $(DESTDIR)$(MANDIR)/man8/syslogtocern.8
+ 
+ clean:
+ 	rm -f $(CLEANFILES)
Index: www/thttpd/patches/patch-extras_htpasswd.c
===================================================================
RCS file: www/thttpd/patches/patch-extras_htpasswd.c
diff -N www/thttpd/patches/patch-extras_htpasswd.c
--- /dev/null
+++ www/thttpd/patches/patch-extras_htpasswd.c
@@ -0,0 +1,70 @@
+$NetBSD$
+
+Not a CVE, two things in the htpasswd utility.
+
+The line buffers are MAX_STRING_LEN (256) while a .htpasswd line is
+"user:hash".  The hash of a modern crypt(3) runs to about a hundred
+characters, so a line written by any other tool does not fit, and
+my_getline() truncates at the limit without saying so; the remainder is
+then read as the next line.  Reading an existing file in order to add a
+user to it therefore corrupted it.  FreeBSD ports, Debian and Fedora all
+enlarge these buffers.
+
+fgets() is not checked when the password comes in on stdin, so pass is
+left uninitialised if it fails, and a leading NUL byte leaves strlen()
+at 0; either way pass[strlen(pass)-1] reads before the buffer.  Both
+paths fire under AddressSanitizer on the routine extracted unchanged
+from 2.29 (empty stdin, and a line starting with a NUL byte).  No other
+packaging fixes this one.
+
+--- extras/htpasswd.c.orig
++++ extras/htpasswd.c
+@@ -20,6 +20,12 @@
+ #define CR 13
+ 
+ #define MAX_STRING_LEN 256
++/* A .htpasswd line is "user:hash".  The hash of a modern crypt(3) is around a
++** hundred characters, so a line does not fit in MAX_STRING_LEN.  my_getline()
++** truncates silently at its limit and the remainder is then read as the next
++** line, so reading an existing file to update it corrupted it.
++*/
++#define MAX_LINE_LEN (MAX_STRING_LEN + 1 + 256)
+ 
+ int tfd;
+ char temp_template[] = "/tmp/htp.XXXXXX";
+@@ -112,8 +118,13 @@
+ 
+     if ( ! isatty( fileno( stdin ) ) )
+ 	{
+-	(void) fgets( pass, sizeof(pass), stdin );
+-	if ( pass[strlen(pass) - 1] == '\n' )
++	/* fgets() can fail, leaving pass uninitialised, and a NUL byte on
++	** stdin leaves strlen() at 0; either way pass[strlen(pass)-1] would
++	** read before the buffer.
++	*/
++	if ( fgets( pass, sizeof(pass), stdin ) == (char*) 0 )
++	    pass[0] = '\0';
++	if ( pass[0] != '\0' && pass[strlen(pass) - 1] == '\n' )
+ 	    pass[strlen(pass) - 1] = '\0';
+ 	pw = pass;
+ 	}
+@@ -149,8 +160,8 @@
+ int main(int argc, char *argv[]) {
+     FILE *tfp,*f;
+     char user[MAX_STRING_LEN];
+-    char line[MAX_STRING_LEN];
+-    char l[MAX_STRING_LEN];
++    char line[MAX_LINE_LEN];
++    char l[MAX_LINE_LEN];
+     char w[MAX_STRING_LEN];
+     char command[MAX_STRING_LEN];
+     int found;
+@@ -188,7 +199,7 @@
+     user[sizeof(user)-1] = '\0';
+ 
+     found = 0;
+-    while(!(my_getline(line,MAX_STRING_LEN,f))) {
++    while(!(my_getline(line,MAX_LINE_LEN,f))) {
+         if(found || (line[0] == '#') || (!line[0])) {
+             putline(tfp,line);
+             continue;
Index: www/thttpd/patches/patch-index.html
===================================================================
RCS file: www/thttpd/patches/patch-index.html
diff -N www/thttpd/patches/patch-index.html
--- /dev/null
+++ www/thttpd/patches/patch-index.html
@@ -0,0 +1,18 @@
+$NetBSD$
+
+Add the NetBSD logo to the sample index page.  The image it points at
+is sitedrivenby.gif, which the package fetches as a second distfile and
+installs beside this page in share/thttpd.
+
+--- index.html.orig	2005-05-13 20:20:35.000000000 +0000
++++ index.html
+@@ -9,6 +9,9 @@
+ 
+ <P>
+ Here's a link to the <A HREF="http://www.acme.com/software/thttpd/";>thttpd web pages</A>.
++<A HREF="http://www.netbsd.org/";>
++<IMG ALIGN=RIGHT SRC="sitedrivenby.gif" border=0 ALT="Site driven by NetBSD">
++</A>
+ 
+ </BODY>
+ </HTML>
Index: www/thttpd/patches/patch-libhttpd.c
===================================================================
RCS file: www/thttpd/patches/patch-libhttpd.c
diff -N www/thttpd/patches/patch-libhttpd.c
--- /dev/null
+++ www/thttpd/patches/patch-libhttpd.c
@@ -0,0 +1,44 @@
+$NetBSD$
+
+Not a security fix, and not an underflow.  The stock code
+
+	i = strlen( hc->origfilename ) - strlen( hc->pathinfo );
+	if ( i > 0 && strcmp( &hc->origfilename[i], hc->pathinfo ) == 0 )
+	    hc->origfilename[i - 1] = '\0';
+
+already prevents the index from going negative: the "i > 0" test means
+origfilename[i-1] is only reached with i >= 1.  I checked this after
+mistaking it for the same shape as the underflows in
+patch-CVE-2007-0158; it is not one.
+
+What it does change is behaviour.  When PATH_INFO is the whole of
+origfilename (i == 0) the stock code leaves origfilename alone, so the
+pathinfo part is not removed from it as the comment above it says it
+should be.  This makes that case set origfilename to the empty string.
+FreeBSD ports and Debian both carry the same change; Debian files it
+under "path-info" rather than as a security patch, which is the right
+reading.
+
+Included because the neighbouring CVE patches touch the same file and a
+reader will otherwise wonder why this one spot is left as it is.  Drop
+this patch if the behaviour change is not wanted -- the CVE patches do
+not depend on it.
+
+--- libhttpd.c.orig
++++ libhttpd.c
+@@ -2351,8 +2351,13 @@
+ 	{
+ 	int i;
+ 	i = strlen( hc->origfilename ) - strlen( hc->pathinfo );
+-	if ( i > 0 && strcmp( &hc->origfilename[i], hc->pathinfo ) == 0 )
+-	    hc->origfilename[i - 1] = '\0';
++	if ( i >= 0 && strcmp( &hc->origfilename[i], hc->pathinfo ) == 0 )
++	    {
++	    if ( i == 0 )
++		hc->origfilename[0] = '\0';
++	    else
++		hc->origfilename[i - 1] = '\0';
++	    }
+ 	}
+ 
+     /* If the expanded filename is an absolute path, check that it's still
Index: www/thttpd/patches/patch-mmc.c
===================================================================
RCS file: www/thttpd/patches/patch-mmc.c
diff -N www/thttpd/patches/patch-mmc.c
--- /dev/null
+++ www/thttpd/patches/patch-mmc.c
@@ -0,0 +1,27 @@
+$NetBSD$
+
+Turn off mmap on NetBSD up to 1.5L (__NetBSD_Version__ 105120000) and
+include <sys/param.h> so that version is defined.
+
+Before UBC arrived in 1.5L, mmap and read were not kept in sync, so
+thttpd went on serving the old contents of a page after it had been
+edited until it was restarted.  From PR pkg/25487, where Hauke Fath
+reported it on 1.5.4 and Michael Santos wrote this hunk.
+
+--- mmc.c.orig	2015-11-05 18:13:49.000000000 +0000
++++ mmc.c
+@@ -37,6 +37,14 @@
+ #include <fcntl.h>
+ #include <syslog.h>
+ #include <errno.h>
++
++#if defined(__NetBSD__)
++#include <sys/param.h>
++#endif
++
++#if (defined(__NetBSD__) && __NetBSD_Version__ <= 105120000)
++#undef HAVE_MMAP
++#endif
+ 
+ #ifdef HAVE_MMAP
+ #include <sys/mman.h>
Index: www/thttpd/patches/patch-thttpd.c
===================================================================
RCS file: www/thttpd/patches/patch-thttpd.c
diff -N www/thttpd/patches/patch-thttpd.c
--- /dev/null
+++ www/thttpd/patches/patch-thttpd.c
@@ -0,0 +1,67 @@
+$NetBSD$
+
+Not a CVE: the access log is created world-readable.  Both places that
+open it use fopen(logfile, "a"), so a log that does not exist yet is
+created 0666 & ~umask -- 0644 under the usual umask.  Every line holds
+the request line, the Referer and the User-Agent, and on an
+authenticated directory the remote user name, so it should not be
+readable by every local user.  This matters most after log rotation,
+where the file is gone and thttpd recreates it on SIGHUP.
+
+Created with 0640 instead.  open() rather than a chmod() after fopen()
+so that there is no window in which the file exists with the wider
+mode, and so that a log the administrator already created keeps the
+mode they chose -- a chmod() would overwrite it on every start.
+
+FreeBSD ports and Fedora both fix this, but with a chmod() after the
+fopen(): FreeBSD to 0640, Fedora to 0600.  Fedora additionally disables
+the fchown() below, which stops thttpd handing the log to the user it
+drops privileges to, so it cannot re-open the log afterwards.  The
+fchown() is left alone here.
+
+--- thttpd.c.orig
++++ thttpd.c
+@@ -327,6 +327,25 @@
+     }
+ 
+ 
++/* Open the log file for appending.  A log that has to be created is created
++** without the world-readable bit: every line holds the request, the Referer
++** and the User-Agent, and on an authenticated directory the remote user name.
++** A file that already exists keeps the mode the administrator gave it.  This
++** uses open() rather than fopen() so that there is no window in which the
++** file exists with the wider mode.
++*/
++static FILE*
++open_logfile( char* lf )
++    {
++    int fd;
++
++    fd = open( lf, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP );
++    if ( fd < 0 )
++	return (FILE*) 0;
++    return fdopen( fd, "a" );
++    }
++
++
+ static void
+ re_open_logfile( void )
+     {
+@@ -339,7 +358,7 @@
+     if ( logfile != (char*) 0 && strcmp( logfile, "-" ) != 0 )
+ 	{
+ 	syslog( LOG_NOTICE, "re-opening logfile" );
+-	logfp = fopen( logfile, "a" );
++	logfp = open_logfile( logfile );
+ 	if ( logfp == (FILE*) 0 )
+ 	    {
+ 	    syslog( LOG_CRIT, "re-opening %.80s - %m", logfile );
+@@ -428,7 +447,7 @@
+ 	    logfp = stdout;
+ 	else
+ 	    {
+-	    logfp = fopen( logfile, "a" );
++	    logfp = open_logfile( logfile );
+ 	    if ( logfp == (FILE*) 0 )
+ 		{
+ 		syslog( LOG_CRIT, "%.80s - %m", logfile );
Index: www/thttpd/files/README.pkgsrc
===================================================================
RCS file: www/thttpd/files/README.pkgsrc
diff -N www/thttpd/files/README.pkgsrc
--- /dev/null
+++ www/thttpd/files/README.pkgsrc
@@ -0,0 +1,16 @@
+makeweb and the web group
+=========================
+
+makeweb lets a user create a public_html directory under the web root.
+To do that it has to be set-group-id to the group that owns the web
+root; pkgsrc installs it without that bit, because making a program
+set-group-id is the administrator's decision, not the package's.
+
+If you want to use it:
+
+	chgrp <group> @PREFIX@/sbin/makeweb
+	chmod 2755 @PREFIX@/sbin/makeweb
+
+The group thttpd's own Makefile suggests is "www".
+
+If you do not use makeweb, leave it as it is.
Index: doc/pkg-vulnerabilities
===================================================================
RCS file: /cvsroot/pkgsrc/doc/pkg-vulnerabilities,v
retrieving revision 1.794
diff -u -r1.794 pkg-vulnerabilities
--- doc/pkg-vulnerabilities
+++ doc/pkg-vulnerabilities
@@ -1559,7 +1559,7 @@
 gdk-pixbuf<0.22.0nb6	arbitrary-code-execution	https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2005-3186
 acid-[0-9]*		cross-site-scripting	http://secunia.com/advisories/17552/
 acid-[0-9]*		sql-injection		http://secunia.com/advisories/17552/
-thttpd<2.25bnb4		insecure-temp-files	http://secunia.com/advisories/17454/
+thttpd<2.29nb1		insecure-temp-files	https://nvd.nist.gov/vuln/detail/CVE-2005-3124
 rar-linux<3.5.1		format-string		http://secunia.com/advisories/17524/
 rar-linux<3.5.1		buffer-overflow		http://secunia.com/advisories/17524/
 gaim-encryption<2.39	denial-of-service		https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2005-4693
@@ -6151,7 +6151,7 @@
 ap{2,22}-modsecurity{,2}<2.6.6	remote-security-bypass		http://secunia.com/advisories/49576/
 apache-roller<5.0.1	cross-site-scripting		http://secunia.com/advisories/49593/
 mini_httpd-[0-9]*	escape-sequence-injection	https://nvd.nist.gov/vuln/detail/CVE-2009-4490
-thttpd-[0-9]*		escape-sequence-injection	https://nvd.nist.gov/vuln/detail/CVE-2009-4491
+thttpd<2.29nb1		escape-sequence-injection	https://nvd.nist.gov/vuln/detail/CVE-2009-4491
 wordpress<3.4.1	multiple-vulnerabilities	http://wordpress.org/news/2012/06/wordpress-3-4-1/
 typo3<4.5.17		cross-site-scripting	https://typo3.org/teams/security/security-bulletins/typo3-core/typo3-core-sa-2012-003/
 typo3>=4.6.0<4.6.10	cross-site-scripting	https://typo3.org/teams/security/security-bulletins/typo3-core/typo3-core-sa-2012-003/
@@ -18469,7 +18469,7 @@
 quagga-[0-9]*		denial-of-service	https://nvd.nist.gov/vuln/detail/CVE-2012-5521
 ruby{22,24,25,26}-net-ldap<0.16.2	weak-cryptography	https://nvd.nist.gov/vuln/detail/CVE-2014-0083
 tahoe-lafs<1.8.3	arbitrary-file-deletion	https://nvd.nist.gov/vuln/detail/CVE-2011-3617
-thttpd-[0-9]*		denial-of-service	https://nvd.nist.gov/vuln/detail/CVE-2012-5640
+thttpd<2.29nb1		denial-of-service	https://nvd.nist.gov/vuln/detail/CVE-2012-5640
 vsftpd<2.3.5		privilege-escalation	https://nvd.nist.gov/vuln/detail/CVE-2011-2523
 wide-dhcpv6-[0-9]*	shell-command-injection		https://nvd.nist.gov/vuln/detail/CVE-2011-2717
 xscreensaver<5.14	authentication-bypass	https://nvd.nist.gov/vuln/detail/CVE-2011-2187
@@ -18700,7 +18700,7 @@
 matio-[0-9]*	denial-of-service		https://nvd.nist.gov/vuln/detail/CVE-2019-20019
 matio-[0-9]*	stack-overflow			https://nvd.nist.gov/vuln/detail/CVE-2019-20020
 upx-[0-9]*	heap-overflow			https://nvd.nist.gov/vuln/detail/CVE-2019-20021
-thttpd-[0-9]*	buffer-underflow		https://nvd.nist.gov/vuln/detail/CVE-2007-0158
+thttpd<2.29nb1	buffer-underflow		https://nvd.nist.gov/vuln/detail/CVE-2007-0158
 upx-[0-9]*	denial-of-service		https://nvd.nist.gov/vuln/detail/CVE-2019-20051
 upx-[0-9]*	denial-of-service		https://nvd.nist.gov/vuln/detail/CVE-2019-20053
 libsixel<1.8.5	denial-of-service		https://nvd.nist.gov/vuln/detail/CVE-2019-20056




Home | Main Index | Thread Index | Old Index