#!/bin/bash
#
# Copyright (C) 2018-2019 Univention GmbH
#
# http://www.univention.de/
#
# All rights reserved.
#
# The source code of this program is made available
# under the terms of the GNU Affero General Public License version 3
# (GNU AGPL V3) as published by the Free Software Foundation.
#
# Binary versions of this program provided by Univention to you as
# well as other copyrighted, protected or trademarked materials like
# Logos, graphics, fonts, specific documentations and configurations,
# cryptographic keys etc. are subject to a license agreement between
# you and Univention and not subject to the GNU AGPL V3.
#
# In the case you use this program under the terms of the GNU AGPL V3,
# the program is provided in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License with the Debian GNU/Linux or Univention distribution in file
# /usr/share/common-licenses/AGPL-3; if not, see
# .
VERSION="44"
VERSION_NAME="4.4"
MIN_VERSION="4.3-3"
UPDATER_LOG="/var/log/univention/updater.log"
# stdout to screen and log
exec > >(exec tee -ia "$UPDATER_LOG")
# stderr to log
exec 2>>"$UPDATER_LOG"
eval "$(univention-config-registry shell)"
##########
# helper #
##########
# shell-univention-lib is probably not installed, so use a local function
is_ucr_true () {
local value
value="$(/usr/sbin/univention-config-registry get "$1")"
case "$(echo -n "$value" | tr '[:upper:]' '[:lower:]')" in
1|yes|on|true|enable|enabled) return 0 ;;
0|no|off|false|disable|disabled) return 1 ;;
*) return 2 ;;
esac
}
ignore_check () {
local var="$1"
if is_ucr_true "$var"; then
echo -n "Ignoring test as requested by $var " 1>&2
return 0
fi
return 1
}
##############################################
# readonly checks here, before release notes #
##############################################
update_check_min_version () {
if ! dpkg --compare-versions "$MIN_VERSION" le "${version_version}-${version_patchlevel}"
then
echo -e "\tThe system needs to be at least at version $MIN_VERSION in order to update!"
return 1
fi
}
# check for hold packages
update_check_hold_packages () {
local var="update$VERSION/ignore_hold"
ignore_check "$var" && return 100
hold_packages=$(LC_ALL=C dpkg -l | grep ^h | awk '{print $2}')
if [ -n "$hold_packages" ]; then
echo -e "\tWARNING: Some packages are marked as hold -- this may interrupt the update and result in an inconsistent system!"
echo -e "\tPlease check the following packages and unmark them or set the UCR variable $var to yes"
for hp in $hold_packages; do
echo -e "\t- $hp"
done
return 1
fi
}
# Bug #44650 begin - check slapd on member
update_check_slapd_on_member () {
local var="update$VERSION/ignore_slapd_on_member"
ignore_check "$var" && return 100
if [ -e "$(which slapd)" -a "$server_role" = "memberserver" ]; then
echo -e "\tThe ldap server is installed on your memberserver. This is not supported"
echo -e "\tand may lead to problems during the update. Please deinstall the package"
echo -e "\t*slapd* from this system with either the command line tool univention-remove "
echo -e "\t -> univention-remove slapd"
echo -e "\tor via the package management in the Univention Management Console."
echo -e "\tMake sure that only the package slapd gets removed!"
echo -e "\tThis check can be disabled by setting the UCR variable"
echo -e "\t$var to yes."
return 1
fi
}
# check /usr on separate file system
update_check_user_mountpoint () {
if mountpoint -q /usr; then
echo -e "\t/usr/ seems to be a separate file system, which is no longer supported."
echo -e "\tMounting file systems nowadays requires many helpers, which use libraries"
echo -e "\tand other resources from /usr/ by default. With a separate /usr/ they"
echo -e "\toften break in subtle ways or lead to hard to debug boot problems."
echo -e "\tAs such the content of /usr/ must be moved to the root file system before"
echo -e "\tthe system can be upgraded to UCS-4.2. This procedure should be performed"
echo -e "\tmanually and might require resizing the file systems. It is described at"
echo -e "\t."
return 1
fi
}
update_check_ldap_schema () {
if [ -x /usr/sbin/slapschema ]; then
if ! /usr/sbin/slapschema 1>&2; then
echo -e "\tThere is a problem with the LDAP schema on this system."
echo -e "\tPlease check $UPDATER_LOG or run 'slapschema' manually."
return 1
fi
fi
}
update_check_valid_machine_credentials () {
if [ -f /var/univention-join/joined -a ! -f /etc/machine.secret ]
then
echo -e "\tThe credentials for the machine account could not be found!"
echo -e "\tPlease re-join this system."
return 1
fi
}
update_check_ldap_connection () {
if [ -n "$server_role" -a "$server_role" != "basesystem" -a -n "$ldap_base" -a -n "$ldap_hostdn" ]
then
ldapsearch -x -D "$ldap_hostdn" -w "$(< /etc/machine.secret)" -b "$ldap_base" -s base &>/dev/null
if [ $? -eq 49 ]
then
echo -e "\tA LDAP connection to the configured LDAP servers with the machine"
echo -e "\taccount has failed (invalid credentials)!"
echo -e "\tThis MUST be fixed before the update can continue."
echo -e "\tThis problem can be corrected by setting the content of the file"
echo -e "\t/etc/machine.secret to the password of the computer object using"
echo -e "\tUnivention Management Console."
return 1
fi
fi
}
# check that no apache configuration files are manually adjusted; Bug #43520
update_check_overwritten_umc_templates () {
local var="update$VERSION/ignore_apache_template_checks"
ignore_check "$var" && return 100
univention-check-templates 2>/dev/null | grep /etc/univention/templates/files/etc/apache2/sites-available/ 1>&2
if [ $? = 0 ]; then
echo -e "\tWARNING: There are modified Apache configuration files in /etc/univention/templates/files/etc/apache2/sites-available/."
echo -e "\tPlease restore the original configuration files before upgrading and apply the manual changes again after the upgrade succeeded."
echo -e "\tThis check can be skipped by setting the UCR"
echo -e "\tvariable $var to yes."
return 1
fi
}
update_check_package_status () {
if dpkg -l | LC_ALL=C grep "^[a-zA-Z][A-Z] " 1>&2
then
echo -e "\tThe package state on this system is inconsistent."
echo -e "\tPlease run 'dpkg --configure -a' manually"
return 1
fi
}
# check for DC Master UCS version
update_check_master_version () {
local var="update$VERSION/ignore_version"
ignore_check "$var" && return 100
if [ -f /var/univention-join/joined ]; then
if [ "$server_role" != domaincontroller_master -a "$server_role" != basesystem ]; then
master_version="$(univention-ssh /etc/machine.secret ${hostname}\$@$ldap_master /usr/sbin/ucr get version/version 2>/dev/null)" 1>&2
master_patchlevel="$(univention-ssh /etc/machine.secret ${hostname}\$@$ldap_master /usr/sbin/ucr get version/patchlevel 2>/dev/null)" 1>&2
if dpkg --compare-versions "${master_version}-${master_patchlevel}" le "${version_version}-${version_patchlevel}"
then
echo -e "\tYour domain controller master is still on version $master_version-$master_patchlevel."
echo -e "\tIt is strongly recommended that the domain controller master is"
echo -e "\talways the first system to be updated during a release update."
echo -e "\tThis check can be skipped by setting the UCR"
echo -e "\tvariable $var to yes."
return 1
fi
fi
fi
}
update_check_disk_space () {
local var="update$VERSION/checkfilesystems"
ignore_check "$var" && return 100
while read partition size usersize; do
if ! [ `df -P "$partition" | tail -n1 | awk '{print $4}'` -gt "$size" ]; then
echo -e "\tNot enough space in $partition, need at least $usersize."
echo -e "\tThis may interrupt the update and result in an inconsistent system!"
echo -e "\tIf necessary you can skip this check by setting the value of the"
echo -e "\tconfig registry variable $var to \"no\"."
echo -e "\tBut be aware that this is not recommended!"
if [ "$partition" = "/boot" -a "$update44_pruneoldkernel" != "yes" ] ; then
echo
echo -e "\tOld kernel versions on /boot can be pruned automatically during"
echo -e "\tnext update attempt by setting config registry variable"
echo -e "\tupdate${VERSION}/pruneoldkernel to \"yes\"."
fi
return 1
fi
done < <(
echo "/var/cache/apt/archives" "4000000" "4000 MB"
echo "/boot" "100000" "100 MB"
echo "/" "4000000" "4000 MB"
)
}
# block if failed.ldif exists
update_check_failed_ldif() {
if [ -e /var/lib/univention-directory-replication/failed.ldif ]; then
echo -e "\tA failed.ldif exists."
echo -e "\tPlease check https://help.univention.com/t/what-to-do-if-a-failed-ldif-is-found/6432 for further information."
echo -e "\tThe update can be started after the failed.ldif has been removed."
return 1
fi
}
# stop if md5 based "Signature Algorithm" is used in tls certificate
update_check_md5_signature_is_used () {
local cert_path="/etc/univention/ssl/"$hostname"."$domainname"/cert.pem"
if [ -f "$cert_path" ]; then
local md5_indicator="Signature Algorithm: md5WithRSAEncryption"
local certopt="no_header,no_version,no_serial,no_signame,no_subject,no_issuer,no_pubkey,no_aux,no_extensions,no_validity"
openssl x509 -in "$cert_path" -text -certopt "$certopt" | grep --quiet "$md5_indicator"
if [ $? -eq 0 ]; then
echo -e "\tThe pre-check of the update found that the certificate file:"
echo -e "\t$cert_path"
echo -e "\tis using md5 as the signature algorithm. This is not supported in"
echo -e "\tUCS ${VERSION_NAME} and later versions. The signature algorithm can be set"
echo -e "\ton the domain controller master with:"
echo -e "\tucr set ssl/default/hashfunction=sha256"
echo -e "\tThe certificate needs to be renewed afterwards. Doing that is"
echo -e "\tdescribed at:"
echo -e "\thttps://help.univention.com/t/renewing-the-ssl-certificates/37"
return 1
fi
fi
}
# block update if system date is too old
update_check_system_date_too_old() {
local system_year=$(date +%Y)
local var="update$VERSION/ignore_system_date"
ignore_check "$var" && return 100
if [ "$system_year" -lt 2018 ] ; then
echo -e "\tThe system date ($(date +%Y-%m-%d)) does not seem to be correct."
echo -e "\tPlease set a current system time before the update, otherwise the"
echo -e "\tupdate will fail if Spamassassin is installed."
echo -e "\tThis check can be disabled by setting the UCR variable"
echo -e "\t$var to yes."
return 1
fi
}
###########################
# release specific checks #
###########################
########
# main #
########
echo
echo "Starting pre-update checks ($(date)):"
echo
# run checks
success=true
declare -A messages
for f in $(declare -F); do
if [[ "$f" =~ update_check_.* ]]; then
name=${f#update_check_}
stat="OK"
printf "%-50s" "Checking $name ... "
stdout=$($f)
ret=$?
if [ $ret -ne 0 ]; then
if [ $ret -eq 100 ]; then
stat="IGNORED"
else
stat="FAIL"
success=false
messages["$name"]="$stdout"
fi
fi
echo "$stat"
fi
done
# summary
RET=0
if ! $success; then
echo
echo "The system can not be updated to UCS $VERSION_NAME due to the following reasons:"
for key in "${!messages[@]}"; do
echo
echo "$key:"
echo "${messages[$key]}" | fmt -u
done
echo
RET=1
fi
exit $RET