forked from mirrors/openup
308 lines
9 KiB
Bash
Executable file
308 lines
9 KiB
Bash
Executable file
#!/bin/sh
|
|
#
|
|
# Copyright (c) 2013, 2014 M:tier Ltd.
|
|
#
|
|
# Permission to use, copy, modify, and distribute this software for any
|
|
# purpose with or without fee is hereby granted, provided that the above
|
|
# copyright notice and this permission notice appear in all copies.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
#
|
|
# Author: Antoine Jacoutot <antoine@mtier.org>
|
|
|
|
# regex taken from fw_update(1)
|
|
set -A _REL -- $(sysctl -n kern.version | sed 's/^OpenBSD \([0-9]\.[0-9]\)\([^ ]*\).*/\1 \2/;q')
|
|
_REL_INT="$(echo ${_REL[0]} | tr -d '.')"
|
|
|
|
########################################################################
|
|
### DO NOT EDIT THIS FILE!!! ###
|
|
### User defined variables: overrides are read from /etc/openup.conf ###
|
|
########################################################################
|
|
# URL to the latest openup version
|
|
OPENUP_URL="https://stable.mtier.org/openup"
|
|
# URL to the certificate that was used to sign the packages (OpenBSD =< 5.4)
|
|
PKG_CERT_URL="https://stable.mtier.org/mtier.cert"
|
|
# fingerprint of the certificate that was used to sign the packages (OpenBSD =< 5.4)
|
|
PKG_CERT_FPRINT="DE:29:0F:7F:B8:0E:36:5A:AF:A9:BF:E0:4E:08:C2:0F:2D:50:16:97"
|
|
# signify(1) public key (OpenBSD >= 5.5)
|
|
PKG_PUBKEY_URL="https://stable.mtier.org/mtier-${_REL_INT}-pkg.pub"
|
|
# PKG_PATH for currently running OpenBSD release
|
|
PKG_PATH_MAIN="http://ftp.fr.openbsd.org/pub/OpenBSD/$(uname -r)/packages/$(arch -s)"
|
|
# PKG_PATH for the corresponding release stable packages service
|
|
PKG_PATH_UPDATE="https://stable.mtier.org/updates/$(uname -r)/$(arch -s)"
|
|
# URL to the latest vuxml (vulnerabilities database)
|
|
VUXML_URL="https://stable.mtier.org/vuxml/${_REL_INT}.xml"
|
|
########################################################################
|
|
### End of user defined variables ###
|
|
########################################################################
|
|
|
|
|
|
_OPENUP_VERSION=14
|
|
_OPENUP_MINREL=53
|
|
|
|
usage() {
|
|
echo
|
|
echo "Usage: ${0##*/} [-K][-Sn|c]" >&2
|
|
echo
|
|
echo "Options:"
|
|
echo " -K do not check for kernel binpatches (when running non GENERIC)"
|
|
echo " -S do not check for package signatures"
|
|
echo " -c check/cron mode, report only (cannot be used with -S and/or -n)"
|
|
echo " -n dry-run mode, only report what would be done"
|
|
echo
|
|
exit 1
|
|
}
|
|
|
|
pr_error() {
|
|
echo "!!! ${@}"
|
|
}
|
|
|
|
if [ "$(id -u)" -ne 0 ]; then
|
|
pr_error "Need root privileges to run this script"
|
|
usage
|
|
fi
|
|
|
|
if [ -f /etc/openup.conf ]; then
|
|
if [ $(stat -f "%SMp%SLp" /etc/openup.conf) != "------" ]; then
|
|
pr_error "Unsecure permissions on /etc/openup.conf; please run:"
|
|
pr_error "chmod 0600 /etc/openup.conf"
|
|
exit 1
|
|
fi
|
|
. /etc/openup.conf
|
|
fi
|
|
|
|
if [ -n "${_REL[1]}" -a "${_REL[1]}" != "-stable" ]; then _badrel=1; fi
|
|
if [ "${_REL_INT}" -lt "${_OPENUP_MINREL}" ]; then _badrel=1; fi
|
|
|
|
if [ -n "${_badrel}" ]; then
|
|
pr_error "${_REL[0]}${_REL[1]} is not a supported release"
|
|
exit 1
|
|
fi
|
|
|
|
_ARCH=$(arch -s)
|
|
_TMPDIR="${TMPDIR:=/tmp}"
|
|
_TMPKEY=$(mktemp -p ${_TMPDIR} .openup-pkg_key.XXXXXXXXXX) || exit 1
|
|
_TMPSPLITCERT=$(mktemp -p ${_TMPDIR} .openup-split_cert.XXXXXXXXXX) || exit 1
|
|
_TMPVUXML=$(mktemp -p ${_TMPDIR} .openup-vuxml.XXXXXXXXXX) || exit 1
|
|
|
|
export PKG_PATH=${PKG_PATH_UPDATE}:${PKG_PATH_MAIN}
|
|
|
|
trap "rm -f ${_TMPDIR}/.openup-*" 1 2 3 13 15
|
|
|
|
pr_bigarrow() {
|
|
if [ -z "${checkmode}" ]; then
|
|
echo "===> ${@}${dryrun}"
|
|
fi
|
|
}
|
|
|
|
pr_smallarrow() {
|
|
if [ -z "${checkmode}" -a -n "${dryrun}" ]; then
|
|
echo "-> ${@}"
|
|
fi
|
|
}
|
|
|
|
cmd.exe() {
|
|
if [ -z "${dryrun}" ]; then
|
|
eval "${@}" || exit 1
|
|
fi
|
|
}
|
|
|
|
get_cert() {
|
|
local _CMD
|
|
|
|
if [ -r /etc/ssl/pkgca.pem ]; then
|
|
split -p '^-----BEGIN CERTIFICATE-----$' /etc/ssl/pkgca.pem ${_TMPSPLITCERT}
|
|
fi
|
|
|
|
for i in ${_TMPSPLITCERT}* ; do
|
|
openssl x509 -noout -in $i -fingerprint 2>/dev/null | \
|
|
grep -q "${PKG_CERT_FPRINT}" && return
|
|
done
|
|
|
|
pr_bigarrow "Downloading certificate"
|
|
_CMD="ftp -Vo ${_TMPKEY} ${PKG_CERT_URL}"
|
|
pr_smallarrow "${_CMD}"
|
|
cmd.exe ${_CMD}
|
|
|
|
pr_bigarrow "Installing certificate"
|
|
_CMD="cat ${_TMPKEY} >>/etc/ssl/pkgca.pem"
|
|
pr_smallarrow "${_CMD}"
|
|
cmd.exe ${_CMD}
|
|
}
|
|
|
|
get_pubkey() {
|
|
[ -r /etc/signify/mtier-${_REL_INT}-pkg.pub ] && return
|
|
local _CMD
|
|
|
|
pr_bigarrow "Downloading public key"
|
|
_CMD="ftp -Vo ${_TMPKEY} ${PKG_PUBKEY_URL}"
|
|
pr_smallarrow "${_CMD}"
|
|
cmd.exe ${_CMD}
|
|
|
|
pr_bigarrow "Installing public key"
|
|
_CMD="install -m0644 ${_TMPKEY} /etc/signify/mtier-${_REL_INT}-pkg.pub"
|
|
pr_smallarrow "${_CMD}"
|
|
cmd.exe ${_CMD}
|
|
}
|
|
|
|
check_openupd() {
|
|
local _CMD _N
|
|
|
|
pr_bigarrow "Checking for openup update"
|
|
_CMD="ftp -Vo - ${OPENUP_URL} | awk -F '=' '/^_OPENUP_VERSION/ { print \$2 }'"
|
|
pr_smallarrow "${_CMD}"
|
|
_N=$(cmd.exe ${_CMD})
|
|
|
|
if [ "${_OPENUP_VERSION}" -lt "${_N}" ]; then
|
|
pr_error "New openup release (version ${_N}) is available; please update with:"
|
|
pr_error "ftp -Vo $(readlink -f $0) ${OPENUP_URL}"
|
|
pr_error "Exiting..."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# check that we have no installed binpatches from a previous release and
|
|
# if so remove the entries manually (we don't want pkg_delete to
|
|
# modify nor error out on installed files from newer release/binpatch)
|
|
rm_old_bp() {
|
|
local _bp
|
|
local _BPDB=$(ls -d /var/db/binpatch/{binpatch-,}[0-9]* 2>/dev/null |grep -v ${_REL})
|
|
local _BPPKG=$(ls -d /var/db/pkg/binpatch* 2>/dev/null |grep -v binpatch${_REL_INT})
|
|
if [ -n "${_BPPKG}" -o -n "${_BPDB}" ]; then
|
|
pr_bigarrow "Removing old release binpatch entries"
|
|
fi
|
|
for _bp in ${_BPPKG} ${_BPDB}; do
|
|
_CMD="rm -rf ${_bp}"
|
|
pr_smallarrow "${_CMD}"
|
|
cmd.exe ${_CMD}
|
|
done
|
|
}
|
|
|
|
update_binpatches() {
|
|
local _BP _CMD
|
|
|
|
_BP=$(pkg_info -Q binpatch${_REL_INT}-${_ARCH} | sed 's/.[^-]*$//' | sort -u | tr '\n' ' ')
|
|
|
|
if [ -n "${_BP}" ]; then
|
|
if [ -n "${exclude_kernel}" ]; then
|
|
_BP=$(echo ${_BP} | sed -e "s,binpatch${_REL_INT}-${_ARCH}-kernel,,g")
|
|
fi
|
|
pr_bigarrow "Installing/updating binpatch(es)"
|
|
_CMD="pkg_add ${pkg_opt} ${_BP}"
|
|
pr_smallarrow "${_CMD}"
|
|
cmd.exe ${_CMD}
|
|
fi
|
|
}
|
|
|
|
update_pkg() {
|
|
local _CMD _PKG
|
|
|
|
_PKG=$(pkg_info -q | grep -v binpatch${_REL_INT}-${_ARCH})
|
|
|
|
if [ -n "${_PKG}" ]; then
|
|
pr_bigarrow "Updating package(s)"
|
|
_CMD="pkg_add -qrz ${pkg_opt}"
|
|
# we don't want to display ${_PKG}, there could be hundreds
|
|
pr_smallarrow "${_CMD} ..."
|
|
_CMD="${_CMD} ${_PKG}"
|
|
cmd.exe ${_CMD}
|
|
fi
|
|
}
|
|
|
|
# this only outputs the most recent vulnerability for each matching pkg
|
|
check_vuxml() {
|
|
local _BP_MATCH _OUTDATED _PAT _PKG_MATCH
|
|
|
|
ftp -Vo ${_TMPVUXML} ${VUXML_URL} >/dev/null || exit 1
|
|
perl -pi -e 's,\$ARCH,'"${_ARCH}"',g' ${_TMPVUXML}
|
|
|
|
_BP_MATCH="$(grep binpatch ${_TMPVUXML} | sed -e 's,<name>,,g;s,</name>,,g;s,\$ARCH,'"${_ARCH}"',g' | sort -u)"
|
|
|
|
if [ -n "${exclude_kernel}" ]; then
|
|
_BP_MATCH=$(echo ${_BP_MATCH} | sed -e "s,binpatch${_REL_INT}-${_ARCH}-kernel,,g")
|
|
fi
|
|
|
|
_PAT=$(pkg_info -q | perl -ne '/^(.*)-(\d[^-]*)[-]?(\w*)(.*)$/ && print "$1\n"' | \
|
|
grep -v binpatch${_REL_INT}-${_ARCH} | \
|
|
while read l; do echo -n "|$l"; done | \
|
|
sed 's/^|//' | sed -e 's,++,\\\++,g')
|
|
_PKG_MATCH=$(grep -Eo '<name>('"${_PAT}"')</name>' ${_TMPVUXML} | \
|
|
sort -u | sed -e 's,<name>,,g;s,</name>,,g')
|
|
|
|
_OUTDATED=$((pkg_add -qnv -Dnosig -Dunsigned ${_BP_MATCH}; pkg_add -qnuv -Dnosig -Dunsigned ${_PKG_MATCH}) 2>/dev/null | \
|
|
grep '^Adding.*(pretending)' | \
|
|
sort -u | \
|
|
sed -e 's,Adding ,,;s,(pretending),,;s,->.*,,' | \
|
|
grep -v '^quirks-' | \
|
|
perl -ne '/^(.*)-(\d[^-]*)[-]?(\w*)(.*)$/ && print "$1\n"')
|
|
|
|
for p in ${_OUTDATED}
|
|
do
|
|
echo "--- ${p} ---\n"
|
|
echo "Available update(s): "
|
|
# XXX how do we print only the 1st matching range in awk?
|
|
awk "/<name>${p}<\/name>/,/<\/vuln>/" ${_TMPVUXML} | \
|
|
sed '/<\/vuln>/,$d' | \
|
|
sed -n -e 's/.*<range><lt>\(.*\)<\/lt><\/range>.*/\1/p' \
|
|
-e 's/.*<p>\(.*\)<\/p>.*/\1/p' | uniq | \
|
|
while read l; do echo -n "${l} "; done
|
|
echo "\n"
|
|
done | fmt | sed '/^$/d'
|
|
}
|
|
|
|
do_i_need_to_reboot() {
|
|
# XXX hardcoded PKG_DBDIR
|
|
local kern_bp_time=$(stat -qf "%Um" /var/db/pkg/binpatch${_REL_INT}-${_ARCH}-kernel-*)
|
|
local wake_up=$(sysctl -n kern.boottime)
|
|
|
|
if [ "${wake_up}" -lt "${kern_bp_time}" ]; then
|
|
pr_error
|
|
pr_error "System must be rebooted after the last kernel update"
|
|
pr_error
|
|
fi
|
|
}
|
|
|
|
while getopts 'KScn' arg; do
|
|
case ${arg} in
|
|
K) exclude_kernel=1 ;;
|
|
S) nosig=1; pkg_opt="${pkg_opt} -Dnosig -Dunsigned" ;;
|
|
c) checkmode=1 ;;
|
|
n) dryrun=" (dry run)"; pkg_opt="${pkg_opt} -n -Dnosig -Dunsigned" ;;
|
|
*) usage ;;
|
|
esac
|
|
done
|
|
[ $# = $(($OPTIND-1)) ] || usage
|
|
|
|
if [ "${checkmode}" ]; then
|
|
if [ -n "${nosig}" -o -n "${dryrun}" ]; then
|
|
usage
|
|
fi
|
|
fi
|
|
|
|
check_openupd
|
|
|
|
if [ "${checkmode}" ]; then
|
|
check_vuxml
|
|
|
|
else
|
|
if [ -z "${nosig}" ]; then
|
|
if [ "${_REL_INT}" -lt 55 ]; then
|
|
get_cert
|
|
else
|
|
get_pubkey
|
|
fi
|
|
fi
|
|
rm_old_bp
|
|
update_binpatches
|
|
update_pkg
|
|
fi
|
|
|
|
do_i_need_to_reboot
|
|
|
|
rm -f ${_TMPDIR}/.openup-*
|