NetBSD/etc/postinstall

528 lines
12 KiB
Plaintext
Raw Normal View History

#!/bin/sh
#
# $NetBSD: postinstall,v 1.7 2002/04/29 08:31:01 lukem Exp $
#
# Copyright (c) 2002 The NetBSD Foundation, Inc.
# All rights reserved.
#
# This code is derived from software contributed to The NetBSD Foundation
# by Luke Mewburn.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
# This product includes software developed by the NetBSD
# Foundation, Inc. and its contributors.
# 4. Neither the name of The NetBSD Foundation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# postinstall
# check for or fix configuration changes that occur
# over time as NetBSD evolves.
#
#
# checks to add:
# - convert ssh to ssh{,d}_config, and deprecate sshd_conf_dir
# - obsolete rc.conf variables
# - critical_filesystems{_beforenet,}
# - defcorename
# - nfsiod_flags
# - amd_master
# - ip6forwarding
# - function to check ${DEST_ETC}/rc.conf and ${DEST_ETC}/rc.conf.d/*
# - de* -> tlp* migration (/etc/ifconfig.de*, $ifconfig_de*,
# dhclient.conf, ...) ?
# - support quiet/verbose mode ?
#
#
# helper functions
#
err()
{
exitval=$1
shift
echo 1>&2 "${PROGNAME}: $*"
exit ${exitval}
}
warn()
{
echo 1>&2 "${PROGNAME}: $*"
}
msg()
{
echo " $*"
}
# additem item description
# add item to list of supported items to check/fix
#
additem()
{
[ $# -eq 2 ] || err 2 "USAGE: additem item description"
items="${items}${items:+ }$1"
eval desc_$1=\"$2\"
}
# cmpdir op src dest mode file [file ...]
# perform op ("check" or "fix") on files in src/ against dest/
#
cmpdir()
{
[ $# -ge 5 ] || err 2 "USAGE: cmpdir op src dest mode file [file ...]"
_op=$1
_src=$2
_dest=$3
_mode=$4
shift 4
_files=$*
if [ ! -d "${_dest}" ]; then
if [ "${_op}" = "check" ]; then
msg "${_dest} is not a directory"
return 1
elif ! mkdir ${_dest} ; then
msg "Can't create missing ${_dest}"
return 1
else
msg "Missing ${_dest} created"
fi
fi
_cmpdir_rv=0
for f in ${_files}; do
fs=${_src}/${f}
fd=${_dest}/${f}
error=""
if [ ! -f "${fd}" ]; then
error="${fd} does not exist"
elif ! cmp -s ${fs} ${fd} ; then
error="${fd} != ${fs}"
else
continue
fi
if [ "${_op}" = "check" ]; then
msg ${error}
_cmpdir_rv=1
elif ! cp ${fs} ${fd}; then
msg "Can't copy ${fs} to ${fd}"
_cmpdir_rv=1
elif ! chmod ${_mode} ${fd}; then
msg "Can't change mode of ${fd} to ${_mode}"
_cmpdir_rv=1
else
msg "Copied ${fs} to ${fd}"
fi
done
return $_cmpdir_rv
}
# rcconf_isset name var --
# load the rcconf for name, and check if obsolete rc.conf(5) variable
# var is defined or not. returns 0 if defined (even to ""), otherwise 1.
#
rcconf_isset()
{
[ $# -eq 2 ] || err 2 "USAGE: rcconf_isset name var"
_name=$1
_var=$2
(
for f in ${DEST_ETC}/rc.conf ${DEST_ETC}/rc.conf.d/${_name}; do
[ -f "${f}" ] && . "${f}";
done
if eval "[ -n \"\${${_var}}\" \
-o \"\${${_var}-UNSET}\" != \"UNSET\" ]"; then
msg "Obsolete rc.conf(5) variable '\$${_var}' found."
exit 0
else
exit 1
fi
)
}
# move_file op src dest --
# check (op == "check") or move (op != "check") from src to dest.
# returns 0 if ok, 1 otherwise.
#
move_file()
{
[ $# -eq 3 ] || err 2 "USAGE: move_file op src dest"
_fm_op=$1
_fm_src=$2
_fm_dest=$3
if [ -f "${_fm_src}" -a ! -f "${_fm_dest}" ]; then
if [ "${_fm_op}" = "check" ]; then
msg "Move ${_fm_src} to ${_fm_dest}"
return 1
fi
if ! mv ${_fm_src} ${_fm_dest}; then
msg "Can't move ${_fm_src} to ${_fm_dest}"
return 1
fi
msg "Moved ${_fm_src} to ${_fm_dest}"
fi
return 0
}
#
# items
# -----
#
#
# defaults
#
additem defaults "/etc/defaults being up to date"
do_defaults()
{
[ -n "$1" ] || err 2 "USAGE: do_defaults fix|check"
cmpdir $1 ${SRC_ETC}/defaults ${DEST_ETC}/defaults 444 \
daily.conf monthly.conf rc.conf security.conf weekly.conf
}
#
# mtree
#
additem mtree "/etc/mtree being up to date"
do_mtree()
{
[ -n "$1" ] || err 2 "USAGE: do_mtree fix|check"
cmpdir $1 ${SRC_ETC}/mtree ${DEST_ETC}/mtree 444 \
NetBSD.dist special
}
#
# rc
#
additem rc "/etc/rc* and /etc/rc.d/ being up to date"
do_rc()
{
[ -n "$1" ] || err 2 "USAGE: do_rc fix|check"
op=$1
rv=0
cmpdir ${op} ${SRC_ETC} ${DEST_ETC} 644 \
rc rc.subr rc.shutdown
rv=$(( ${rv} + $? ))
cmpdir ${op} ${SRC_ETC}/rc.d ${DEST_ETC}/rc.d 555 \
DAEMON LOGIN NETWORKING SERVERS accounting altqd amd \
apmd bootparams bootconf.sh ccd cleartmp cron \
dhclient dhcpd dhcrelay dmesg downinterfaces fsck \
ifwatchd inetd ipfilter ipfs ipmon ipnat ipsec isdnd \
kdc ldconfig lkm1 lkm2 lkm3 local lpd mopd motd \
mountall mountcritlocal mountcritremote mountd moused \
mrouted named ndbootd network newsyslog nfsd \
nfslocking ntpd ntpdate poffd postfix ppp pwcheck \
quota racoon rpcbind raidframe rarpd rbootd root \
route6d routed rtadvd rtsold rwho savecore \
screenblank sendmail securelevel sshd swap1 swap2 \
sysdb sysctl syslogd timed ttys virecover wscons xdm \
xfs ypbind yppasswdd ypserv
rv=$(( ${rv} + $? ))
failed=0
for f in NETWORK gated; do
fd=${DEST_ETC}/rc.d/${f}
[ ! -e "${fd}" ] && continue
if [ "${op}" = "check" ]; then
msg "Remove ${fd}"
failed=1
elif ! rm ${fd}; then
msg "Can't remove ${fd}"
failed=1
else
msg "Removed ${fd}"
fi
done
rv=$(( ${rv} + ${failed} ))
return ${rv}
}
#
# periodic
#
additem periodic "/etc/{daily,weekly,monthly,security} being up to date"
do_periodic()
{
[ -n "$1" ] || err 2 "USAGE: do_periodic fix|check"
cmpdir $1 ${SRC_ETC} ${DEST_ETC} 644 \
daily weekly monthly security
}
#
# ssh
#
additem ssh "ssh configuration file relocation"
do_ssh()
{
[ -n "$1" ] || err 2 "USAGE: do_ssh fix|check"
op=$1
failed=0
_etcssh=${DEST_ETC}/ssh
if [ ! -d "${_etcssh}" ]; then
if [ "${op}" = "check" ]; then
msg "${_etcssh} is not a directory"
failed=1
elif ! mkdir ${_etcssh} ; then
msg "Can't create missing ${_etcssh}"
failed=1
else
msg "Missing ${_etcssh} created"
fi
fi
if [ ${failed} -eq 0 ]; then
for f in \
ssh_known_hosts ssh_known_hosts2 \
ssh_host_dsa_key ssh_host_dsa_key.pub \
ssh_host_rsa_key ssh_host_rsa_key.pub \
ssh_host_key ssh_host_key.pub \
; do
if ! move_file ${op} ${DEST_ETC}/${f} ${_etcssh}/${f};
then
failed=1
fi
done
for f in sshd.conf ssh.conf ; do
# /etc/ssh/ssh{,d}.conf -> ssh{,d}_config
#
if ! move_file ${op} \
${_etcssh}/${f} ${_etcssh}/${f%.conf}_config ;
then
failed=1
fi
# /etc/ssh{,d}.conf -> /etc/ssh/ssh{,d}_config
#
if ! move_file ${op} \
${DEST_ETC}/${f} ${_etcssh}/${f%.conf}_config ;
then
failed=1
fi
done
fi
if [ -f "${_etcssh}/sshd_config" ]; then
sshdconf=${_etcssh}/sshd_config
elif [ -f "${_etcssh}/sshd.conf" ]; then
sshdconf=${_etcssh}/sshd.conf
elif [ -f "${DEST_ETC}/sshd.conf" ]; then
sshdconf=${DEST_ETC}/sshd.conf
else
sshdconf=""
fi
if [ -n "${sshdconf}" ]; then
awk '
$1 ~ /^[Hh][Oo][Ss][Tt][Kk][Ee][Yy]$/ &&
$2 ~ /^\/etc\/+ssh_host(_[dr]sa)?_key$/ {
sub(/\/etc\/+/, "/etc/ssh/");
}
{ print }
' < ${sshdconf} > ${SCRATCHDIR}/sshd_config
if ! cmp -s ${sshdconf} ${SCRATCHDIR}/sshd_config; then
diff ${sshdconf} ${SCRATCHDIR}/sshd_config > \
${SCRATCHDIR}/sshd_config.diffs
if [ "${op}" = "check" ]; then
msg "${sshdconf} needs the following changes:"
failed=1
elif ! cp -f ${SCRATCHDIR}/sshd_config ${sshdconf}; then
msg "${sshdconf} changes not applied:"
failed=1
else
msg "${sshdconf} changes applied:"
fi
while read _line; do
msg " ${_line}"
done < ${SCRATCHDIR}/sshd_config.diffs
fi
fi
if rcconf_isset sshd sshd_conf_dir ; then
failed=1
fi
return ${failed}
}
#
# end of items
# ------------
#
usage()
{
cat 1>&2 << _USAGE_
Usage: ${PROGNAME} [-s srcdir] [-d destdir] operation [item [...]]
Perform post-installation checks and/or fixes on a system's
configuration files. If no items are provided, all checks
or fixes are applied.
Options:
-s srcdir Source directory to compare from. [${SRC_ETC}]
-d destdir Destination directory to check. [${DEST_ETC}]
Operation may be one of:
2002-04-26 19:49:09 +04:00
help display this help
list list available items
check perform post-installation checks on items
fix apply fixes that 'check' determines need to be applied
usage display this usage
_USAGE_
exit 1
}
list()
{
echo "Source directory: ${SRC_ETC}"
echo "Target directory: ${DEST_ETC}"
echo "Supported items:"
echo " Item Description"
echo " ---- -----------"
for i in ${items}; do
eval desc="\${desc_${i}}"
printf " %-12s %s\n" "${i}" "${desc}"
done
}
main()
{
while getopts s:d: ch; do
case ${ch} in
s)
SRC_ETC=${OPTARG} ;;
d)
DEST_ETC=${OPTARG} ;;
*)
usage ;;
esac
done
shift $((${OPTIND} - 1))
[ $# -gt 0 ] || usage
[ -d "${SRC_ETC}" ] || err 1 "${SRC_ETC} is not a directory"
[ -d "${DEST_ETC}" ] || err 1 "${DEST_ETC} is not a directory"
op=$1
shift
case "${op}" in
2002-04-26 19:49:09 +04:00
usage|help)
usage
;;
list)
list
;;
check|fix)
todo=$*
: ${todo:=${items}}
# ensure that all supplied items are valid
#
for i in ${todo}; do
eval desc=\"\${desc_${i}}\"
[ -n "${desc}" ] || err 1 "Unsupported ${op} '"${i}"'"
done
# perform each check/fix
#
items_passed=
items_failed=
for i in ${todo}; do
echo "${i} ${op}:"
( eval do_${i} ${op} )
if [ $? -eq 0 ]; then
items_passed="${items_passed} ${i}"
else
items_failed="${items_failed} ${i}"
fi
done
if [ "${op}" = "check" ]; then
plural="checks"
else
plural="fixes"
fi
echo "${PROGNAME} ${plural} passed:${items_passed}"
echo "${PROGNAME} ${plural} failed:${items_failed}"
;;
*)
warn "Unknown operation '"${op}"'"
usage
;;
esac
}
mkdtemp ()
{
# Make sure we don't loop forever if mkdir will always fail.
[ -d /tmp ] || err 1 /tmp is not a directory
[ -w /tmp ] || err 1 /tmp is not writeable
_base=/tmp/_postinstall.$$
_serial=0
while true; do
_dir=${_base}.${_serial}
mkdir -m 0700 ${_dir} && break
_serial=$((${_serial} + 1))
done
echo ${_dir}
}
# defaults
#
PROGNAME=${0##*/}
SRC_ETC=/usr/src/etc
DEST_ETC=/etc
SCRATCHDIR=$( mkdtemp ) || err 1 "Can't create scratch directory"
trap "/bin/rm -rf ${SCRATCHDIR} ; exit 0" 0 1 2 3 15 # EXIT HUP INT QUIT TERM
umask 022
main $*
exit 0