Module Name:    src
Committed By:   riastradh
Date:           Sun Sep  3 18:31:36 UTC 2023

Modified Files:
        src/usr.sbin/postinstall: postinstall.in

Log Message:
postinstall(8): Handle various certs.conf scenarios gracefully.

Tested the following scenarios:

1. fresh install
   empty /etc/openssl/certs
   default /etc/openssl/certs.conf
   - opensslcertsconf
     [x] check: pass
     [x] fix: pass -- nothing
   - opensslcertsrehash
     [x] check: fail -- needs rehash
     [x] fix: pass -- quietly rehash successfully (go to 4)

2. fresh upgrade
   empty /etc/openssl/certs
   no /etc/openssl/certs.conf
   - opensslcertsconf
     [x] check: fail -- complain missing /etc/openssl/certs.conf
     [x] fix: pass -- install default /etc/openssl/certs.conf (go to 1)
   - opensslcertsrehash
     [x] check: fail -- complain missing /etc/openssl/certs.conf
     - [x] fix: fail -- complain missing /etc/openssl/certs.conf

3. upgrade from certctl, changes to certs
   certctl-managed /etc/openssl/certs
   default /etc/openssl/certs.conf
   - opensslcertsconf
     [x] check: pass
     [x] fix: pass -- nothing
   - opensslcertsrehash
     [x] check: fail -- needs rehash
     [x] fix: pass -- quietly rehash successfully (go to 4)

4. upgrade from certctl, no changes to certs
   certctl-managed /etc/openssl/certs
   default /etc/openssl/certs.conf
   - opensslcertsconf
     [x] check: pass
     [x] fix: pass -- nothing
   - opensslcertsrehash
     [x] check: pass
     [x] fix: pass -- quietly rehash successfully (go to 4)

5. upgrade from mozilla-rootcerts
   populated /etc/openssl/certs
   no /etc/openssl/certs.conf
   - opensslcertsconf:
     [x] check: fail -- complain missing /etc/openssl/certs.conf
     [x] fix: pass -- install manual /etc/openssl/certs.conf (go to 7)
   - opensslcertsrehash:
     [x] check: fail -- complain missing /etc/openssl/certs.conf
     [x] fix: fail -- complain missing /etc/openssl/certs.conf

6. upgrade from mozilla-rootcerts with etcupdate naively
   populated /etc/openssl/certs
   default /etc/openssl/certs.conf
   - opensslcertsconf:
     [x] check: pass
     [x] fix: pass -- nothing
   - opensslcertsrehash:
     [x] check: fail -- complain mismatched certs/ and certs.conf
     [x] fix: fail -- complain mismatched certs/ and certs.conf

7. upgrade from mozilla-rootcerts with etcupdate manually
   populated /etc/openssl/certs
   manual /etc/openssl/certs.conf
   - opensslcertsconf:
     [x] check: pass
     [x] fix: pass -- nothing
   - opensslcertsrehash:
     [x] check: pass
     [x] fix: pass -- skip rehash because manual (go to 7)

XXX Someone should draft automatic tests for postinstall.  It has a
very good track record, but it sure would be nice to automate this
testing rather than redo it each time I make a tiny change.


To generate a diff of this commit:
cvs rdiff -u -r1.54 -r1.55 src/usr.sbin/postinstall/postinstall.in

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.sbin/postinstall/postinstall.in
diff -u src/usr.sbin/postinstall/postinstall.in:1.54 src/usr.sbin/postinstall/postinstall.in:1.55
--- src/usr.sbin/postinstall/postinstall.in:1.54	Mon Aug 28 23:57:08 2023
+++ src/usr.sbin/postinstall/postinstall.in	Sun Sep  3 18:31:36 2023
@@ -1,6 +1,6 @@
 #!/bin/sh
 #
-# $NetBSD: postinstall.in,v 1.54 2023/08/28 23:57:08 riastradh Exp $
+# $NetBSD: postinstall.in,v 1.55 2023/09/03 18:31:36 riastradh Exp $
 #
 # Copyright (c) 2002-2022 The NetBSD Foundation, Inc.
 # All rights reserved.
@@ -1662,24 +1662,126 @@ do_named()
 
 
 #
-#	opensslcerts
+#	opensslcertsconf
 #
 
-additem opensslcerts "build /etc/openssl/certs cache of HTTPS CA certificates"
-do_opensslcerts()
+additem opensslcertsconf "ensure TLS trust anchor configuration exists"
+do_opensslcertsconf()
 {
-	[ -n "$1" ] || err 3 "USAGE: do_opensslcerts fix|check"
+	local certsdir certsconf defaultconf
+
+	[ -n "$1" ] || err 3 "USAGE: do_opensslcertsconf fix|check"
+
+	certsdir="${DEST_DIR}/etc/openssl/certs"
+	certsconf="${DEST_DIR}/etc/openssl/certs.conf"
+	defaultconf="${DEST_DIR}/usr/share/examples/certctl/certs.conf"
 
 	case $1 in
-	check)	# XXX Anything to check?
-		return 0
+	check)	if [ ! -r "$certsconf" ]; then
+			msg "/etc/openssl/certs.conf missing; see certctl(8)"
+			return 1
+		fi
+		;;
+	fix)	# If /etc/openssl/certs.conf is already there, nothing
+		# to do.
+		if [ -r "$certsconf" ]; then
+			msg "/etc/openssl/certs.conf already exists"
+			return 0
+		fi
+
+		# If /etc/openssl/certs is a symlink, or exists but is
+		# not a directory, or is a directory but is nonempty,
+		# then either it's managed by someone else or something
+		# fishy is afoot.  So set it manual in that case.
+		# Otherwise, install the default config file.
+		if [ -h "$certsdir" ] ||
+		    [ -e "$certsdir" -a ! -d "$certsdir" ] ||
+		    ([ -d "$certsdir" ] &&
+			find -f "$certsdir" -- \
+			    -maxdepth 0 -type d -empty -exit 1)
+		then
+			msg "/etc/openssl/certs appears manually configured"
+			cat <<EOF >${certsconf}.tmp
+netbsd-certctl 20230816
+
+# existing /etc/openssl/certs configuration detected by postinstall(8)
+manual
+EOF
+		else
+			msg "installing default /etc/openssl/certs.conf"
+			cp -- "$defaultconf" "${certsconf}.tmp"
+		fi && mv -f -- "${certsconf}.tmp" "$certsconf"
+		;;
+	*)	err 3 "USAGE: do_opensslcerts fix|check"
+		;;
+	esac
+}
+
+
+#
+#	opensslcertsrehash
+#
+
+additem opensslcertsrehash "make /etc/openssl/certs cache of TLS trust anchors"
+do_opensslcertsrehash()
+{
+	local mtreekeys scratchdir
+
+	[ -n "$1" ] || err 3 "USAGE: do_opensslcertsrehash fix|check"
+
+	if [ ! -r "${DEST_DIR}/etc/openssl/certs.conf" ]; then
+		msg "/etc/openssl/certs.conf missing; see certctl(8)"
+		return 1
+	fi
+
+	case $1 in
+	check)	# Create a scratch rehash for comparison.
+		mtreekeys="type,link"
+		scratchdir="${SCRATCHDIR}/opensslcerts"
+		certctl -c "$scratchdir" rehash || return $?
+
+		# This will create ${scratchdir}/.certctl unless the
+		# configuration is manual.  If the configuration is
+		# manual, stop here; nothing to do.  certctl(8) will
+		# have already printed a message about that.
+		#
+		# XXX Grody to rely on the internal structure used by
+		# certctl(8), but less bad than having two versions of
+		# the config parsing logic.
+		if [ ! -f "${scratchdir}/.certctl" ]; then
+			return 0
+		fi
+
+		# Do a dry run of rehashing into the real
+		# /etc/openssl/certs.  This curious extra step ensures
+		# that we report a failure if /etc/openssl/certs
+		# appears to be managed manually, but `manual' was not
+		# specified in /etc/openssl/certs.conf.
+		certctl -n rehash || return $?
+
+		# Compare the trees with mtree(8).  Inconveniently,
+		# mtree returns status zero even if there are missing
+		# or extra files.  So instead of examining the return
+		# status, test for any output.  Empty output means
+		# everything matches; otherwise the mismatch, missing,
+		# or extra files are output.
+		mtree -p "$scratchdir" -c -k "$mtreekeys" \
+		| mtree -p "${DEST_DIR}/etc/openssl/certs" 2>&1 \
+		| {
+			while read -r line; do
+				# mismatch, missing, or extra
+				msg "/etc/openssl/certs needs rehash"
+				exit 1
+			done
+			exit 0
+		}
 		;;
 	fix)	# This runs openssl(1), which is not available as a
 		# build-time tool.  So for now, restrict it to running
 		# on the installed system.
 		case $DEST_DIR in
 		''|/)	;;
-		*)	msg "opensslcerts limited to DEST_DIR=/"
+		*)	msg "opensslcertsrehash limited to DEST_DIR=/"
 			return 1
 			;;
 		esac

Reply via email to