#!/bin/sh # # Copyright (c) 2013 - 2017 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 # Maintainer: M:Tier Ltd. # ChangeLog # https://gitlab.com/mtier/openup/commits/master ######################################################################## ### 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" # signify(1) public key PKG_PUBKEY_URL="https://stable.mtier.org/mtier-$(uname -r | tr -d '.')-pkg.pub" # PKG_PATH for currently running OpenBSD release PKG_PATH_MAIN="https://ftp.fr.openbsd.org/pub/OpenBSD/$(uname -r)/packages/$(arch -s)" # ERRATA_PATH ERRATA_PATH="https://ftp.fr.openbsd.org/pub/OpenBSD/patches/$(uname -r)/common" # PKG_PATH for the corresponding release stable service PKG_PATH_UPDATE="https://stable.mtier.org/updates/$(uname -r)/$(arch -s)" # PKG_PATH addition for the corresponding LTS release stable service #PKG_PATH_UPDATE_LTS="https://user%domain.tld:password@stable.mtier.org/updates-lts/$(uname -r)/$(arch -s)" # URL to the latest vuxml (vulnerabilities database) VUXML_URL="https://stable.mtier.org/vuxml/$(uname -r | tr -d '.').xml" # fetch command (must behave like "ftp -o"); e.g. "wget -qO" FETCH="ftp -MVo" # exclusion list: pkg names without version/flavor, separated by space EXCLUDE_PKG="" ######################################################################## ### End of user defined variables ### ######################################################################## usage() { echo echo "Usage: ${0##*/} [-K][-Se|c]" >&2 echo echo "Options:" echo " -K do not check for kernel binpatches (when running non GENERIC)" echo " -N do not check for syspatches" echo " -S ignore binpatch/package signatures" echo " -c check/cron mode, report only (cannot be used with -S)" echo " -e echo the PKG_PATH that ${0##*/} would use" echo exit 1 } pr_err() { echo "!!! ${@}" } bye_bye() { rm -rf ${_TMPDIR} ${_PID} exit 1 } pr() { if [ -z "${checkrun}" ]; then echo "===> ${@}" fi } get_key() { [ -r /etc/signify/mtier-${_REL_INT}-pkg.pub ] && return pr "Downloading and installing public key" ${FETCH} ${_TMPKEY} ${PKG_PUBKEY_URL} || bye_bye install -m0644 ${_TMPKEY} /etc/signify/mtier-${_REL_INT}-pkg.pub || bye_bye } show_env() { echo PKG_PATH=${PKG_PATH_UPDATE_LTS}:${PKG_PATH_UPDATE}:${PKG_PATH_MAIN} exit 0 } check_openupd() { local _U pr "Checking for openup update" _U="${FETCH} - ${OPENUP_URL} | awk -F '=' '/^_OPENUP_VERSION/ { print \$2 }'" _U=$(eval $_U) if [ -z "${_U}" ]; then pr_err "Cannot retrieve ${OPENUP_URL}" pr_err "Please verify your Internet connection, proxy settings and firewall." bye_bye fi if [ "${_OPENUP_VERSION}" -lt "${_U}" ]; then pr_err "New openup release (version ${_U}) available; please update with:" pr_err "${FETCH} $(readlink -f $0) ${OPENUP_URL}" bye_bye 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 "Removing old release binpatch entries" fi for _bp in ${_BPPKG} ${_BPDB}; do rm -rf ${_bp} done } update_syspatches() { pr "Installing/updating syspatches" syspatch if [ $? -gt 0 ]; then pr_err "syspatch failed; please run syspatch manually" bye_bye fi } update_binpatches() { local _BP _b _e # binpatches can only be found in PKG_PATH_UPDATE{,_LTS) and we # want to make sure we search in all paths and don't stop at the # first match we find for i in ${PKG_PATH_UPDATE_LTS} ${PKG_PATH_UPDATE}; do _BP="$(pkg_info -Q binpatch${_REL_INT}-${_ARCH} | sed 's/.[^-]*$//' | sort -u)${_BP:+ ${_BP}}" done if [ -n "${_BP}" ]; then for _e in ${EXCLUDE_PKG}; do set -A _BP -- ${_BP} _BP="$(for _b in ${_BP[@]}; do echo ${_b} | grep -v "^${_e}$"; done)" done _BP=$(echo "${_BP}" | tr '\n' ' ') pr "Installing/updating binpatch(es)" pkg_add ${pkgopt} ${_BP} || bye_bye fi } update_pkg() { local _PKG _e _p _PKG=$(pkg_info -q | grep -v binpatch${_REL_INT}-${_ARCH}) if [ -n "${_PKG}" ]; then for _e in ${EXCLUDE_PKG}; do set -A _PKG -- ${_PKG} _PKG="$(for _p in ${_PKG[@]}; do echo ${_p} | grep -v "^${_e}-.*"; done)" done _PKG=$(echo "${_PKG}" | tr '\n' ' ') pr "Updating package(s)" pkg_add -quz ${pkgopt} ${_PKG} || bye_bye fi } # this only outputs the missing syspatches on the system check_syspatches() { _SYSPATCHES=$(syspatch -c) for _p in ${_SYSPATCHES}; do ${FETCH} ${_TMPERRATA} ${ERRATA_PATH}/${_p}.patch.sig [ -e ${_TMPERRATA} ] || continue echo "--- ${_p} ---" echo -n "Available errata: " awk '/OpenBSD/{f=1;next} /Apply/{f=0;next} f' ${_TMPERRATA} | grep -ve '^$' done } # this only outputs the most recent vulnerability for each matching pkg check_vuxml() { local _BP_MATCH _OUTDATED _PKG_MATCH _b _e _p ${FETCH} ${_TMPVUXML} ${VUXML_URL} || bye_bye perl -pi -e 's,\$ARCH,'"${_ARCH}"',g' ${_TMPVUXML} if [ "${_REL_INT}" -lt 61 ]; then _BP_MATCH="$(grep binpatch ${_TMPVUXML} | sed -e 's,,,g;s,,,g;s,\$ARCH,'"${_ARCH}"',g' | sort -u)" for _e in ${EXCLUDE_PKG}; do set -A _BP_MATCH -- ${_BP_MATCH} _BP_MATCH="$(for _b in ${_BP_MATCH[@]}; do echo ${_b} | grep -v "^${_e}$"; done)" done fi _PKG_MATCH=$(pkg_info -q | grep -v binpatch${_REL_INT}-${_ARCH}) for _e in ${EXCLUDE_PKG}; do set -A _PKG_MATCH -- ${_PKG_MATCH} _PKG_MATCH="$(for _p in ${_PKG_MATCH[@]}; do echo ${_p} | grep -v "^${_e}-.*"; done)" done if [ "${_REL_INT}" -lt 61 ]; then # set to "quirks" if empty to prevent running pkg_add against an empty pkg list _OUTDATED=$((pkg_add -Iqn -Dnosig -Dunsigned ${_BP_MATCH:=quirks}; pkg_add -Iqnuz -Dnosig -Dunsigned ${_PKG_MATCH:=quirks}) 2>&1 | \ grep '^NOT CHECKING DIGITAL SIGNATURE FOR ' | \ sed -e 's,^NOT CHECKING DIGITAL SIGNATURE FOR ,,g' | \ grep -v '^quirks-' | \ perl -ne '/^(.*)-(\d[^-]*)[-]?(\w*)(.*)$/ && print "$1\n"' | \ sort -u) else # set to "quirks" if empty to prevent running pkg_add against an empty pkg list _OUTDATED=$((pkg_add -Inuvz -Dnosig -Dunsigned ${_PKG_MATCH:=quirks}) 2>&1 | \ grep '^Adding.*(pretending)' | sort -u | sed -e 's,Adding ,,;s,(pretending),,;s,->.*,,' | \ grep -v '^quirks-' | \ perl -ne '/^(.*)-(\d[^-]*)[-]?(\w*)(.*)$/ && print "$1\n"' | \ sort -u) fi 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 "/${p}<\/name>/,/<\/vuln>/" ${_TMPVUXML} | \ sed '/<\/vuln>/,$d' | \ sed -n -e 's/.*\(.*\)<\/lt><\/range>.*/\1/p' \ -e 's/.*

\(.*\)<\/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 osversion=$(sysctl -n kern.osversion) local kern_version=$(sysctl -n kern.version | head -1) local booted_version=$(what -s /bsd | tail -1 | tr -d '\t') local booted_time=$(sysctl -n kern.boottime) local kern_time=$(stat -qf "%Um" /bsd) local warn=0 # Check /bsd.booted first if available due to kernel relinking if [ -e /bsd.booted ]; then [ X"${kern_version}" != X"${booted_version}" ] && warn=1 else [ "${booted_time}" -lt "${kern_time}" ] && warn=1 fi if [ ${warn} -gt 0 ]; then pr_err pr_err "System must be rebooted after the last kernel update" pr_err fi } patch_syspatch() { pr_err pr_err "Patching syspatch(8) to use syspatches signed by MTier." pr_err cp /usr/sbin/syspatch /usr/sbin/syspatch.pre-mtier sed -i \ "s,openbsd-\${_OSrev}-syspatch.pub,mtier-\${_OSrev}-pkg.pub,g; \ s,/etc/installurl,/etc/installurl-mtier,g" \ /usr/sbin/syspatch [ -e /etc/installurl-mtier ] || echo https://stable.mtier.org > /etc/installurl-mtier } trap "bye_bye" 1 2 3 13 15 if [ -f /etc/openup.conf ]; then if [ $(stat -f "%SMp%SLp" /etc/openup.conf) != "------" ]; then pr_err "Unsecure permissions on /etc/openup.conf; please run:" pr_err "chmod 0600 /etc/openup.conf" exit 1 fi . /etc/openup.conf fi # 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 '.')" _OPENUP_MINREL=60 _OPENUP_VERSION=33 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_err "${_REL[0]}${_REL[1]} is not a supported release" exit 1 fi while getopts 'KNSce' arg; do case ${arg} in K) if [ "${_REL_INT}" -lt 61 ]; then nokrn=1; fi ;; N) nosyspatch=1 ;; S) nosig=1; pkgopt="${pkgopt} -Dnosig -Dunsigned" ;; c) checkrun=1 ;; e) showenv=1 ;; *) usage ;; esac done [ $# = $(($OPTIND-1)) ] || usage [ -n "${showenv}" ] && show_env if [ "$(id -u)" -ne 0 ]; then pr_err "Need root privileges to run this script" usage fi [ -n "${checkrun}" -a -n "${nosig}" -a -n "${showenv}" ] && usage _ARCH=$(arch -s) _PID="/var/run/${0##*/}.pid" _TMP="${TMPDIR:=/tmp}" _TMPDIR=$(mktemp -dp ${_TMP} .openup-XXXXXXXXXX) || exit 1 _TMPKEY="${_TMPDIR}/key" _TMPVUXML="${_TMPDIR}/vuxml" _TMPERRATA="${_TMPDIR}/errata" export PKG_PATH=${PKG_PATH_UPDATE_LTS}:${PKG_PATH_UPDATE}:${PKG_PATH_MAIN} if [ -f ${_PID} ]; then pr_err "openup is already running ($(cat ${_PID})):" pr_err "${_PID}" exit 1 fi echo $$ >${_PID} if [ -n "${nokrn}" ]; then EXCLUDE_PKG="binpatch${_REL_INT}-${_ARCH}-kernel ${EXCLUDE_PKG}" fi if [ -n "${EXCLUDE_PKG}" ]; then pr "Excluded package(s)/binpatch(es): ${EXCLUDE_PKG}" fi check_openupd if [ -z "${nosyspatch}" -a -e /usr/sbin/syspatch ]; then _sum=$(sha256 -q /usr/sbin/syspatch) case "${_sum}" in # 6.1 syspatch b8b9c4bec128884498b5c3e77a350f42079f7987ef862a1ec452f489403dfbe6) patch_syspatch ;; esac fi if [ "${checkrun}" ]; then if [ "${_REL_INT}" -ge 61 -a -z "${nosyspatch}" ]; then check_syspatches fi check_vuxml else [ -z "${nosig}" ] && get_key rm_old_bp if [ "${_REL_INT}" -lt 61 -a -z "${nosyspatch}" ]; then update_binpatches else [ -z "${nosyspatch}" ] && update_syspatches fi update_pkg fi do_i_need_to_reboot rm -rf ${_TMPDIR} rm ${_PID}