#!/bin/bash
#
# Copyright (C) 2018 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="43"
VERSION_NAME="4.3"
MIN_VERSION="4.2-3"
UPDATER_LOG="/var/log/univention/updater.log"
# stdout to screen and log
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
}
# UCS_VERSION1 is less than or equal to UCS_VERSION2
ucs_version_is_le () {
local version1="$1"
local version2="$2"
python -c 'from univention.lib.ucs import UCS_Version
import sys
master=UCS_Version("'$version1'")
me=UCS_Version("'$version2'")
if master <= me:
sys.exit(1)
'
test $? -ne 0 && return 1
return 0
}
##############################################
# readonly checks here, before release notes #
##############################################
update_check_min_version () {
ucs_version_is_le "$MIN_VERSION" "${version_version}-${version_patchlevel}"
if [ $? -ne 1 ]; 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
ucs_version_is_le "${master_version}-${master_patchlevel}" "${version_version}-${version_patchlevel}"
if [ $? != 0 ]; 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 ! "$update43_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 "\tupdate43/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"
)
}
###########################
# release specific checks #
###########################
# begin bug 46133 - 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 4.3 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
}
# end bug 46133
# begin bug 46118 - Remove support for NT DC
update_check_block_update_of_NT_DC() {
local var="update$VERSION/ignore_samba_nt_dc"
ignore_check "$var" && return 100
if [ "${samba_role}" = "domaincontroller" ]; then
if ! dpkg -l univention-samba | grep -q ^ii; then
return 0
fi
if [ "${server_role}" = "domaincontroller_slave" ]; then
if dpkg -l univention-samba-slave-pdc | grep -q ^ii; then
return 0
fi
fi
echo -e "\tSamba/NT (samba3) Domain Controller is not supported any more."
echo -e "\tPlease migrate this domain to Samba/AD before updating."
echo -e "\tSee https://wiki.univention.de/index.php/Migration_from_Samba_3_to_Samba_4"
echo -e "\tand https://wiki.univention.de/index.php/Best_Practice_Samba_4_Migration"
echo -e "\tThis check can be disabled by setting the UCR variable"
echo -e "\t$var to yes."
return 1
fi
}
# Check for postgresql-9.1 (Bug #44160)
update_check_postgresql91 () {
local var="update$VERSION/ignore_postgresql91"
ignore_check "$var" && return 100
case "$(dpkg-query -W -f '${Status}' postgresql-9.1 2>/dev/null)" in
install*) ;;
*) return 0 ;;
esac
echo -e "\tPostgreSQL-9.1 is no longer supported by UCS-4.3 and must be migrated to"
echo -e "\ta newer version of PostgreSQL. See https://help.univention.com/t/8073 for"
echo -e "\tmore details."
return 1
}
# Bug #46102: Remove Cyrus integration
update_check_cyrus_integration () {
local var="update$VERSION/ignore_cyrus_check"
ignore_check "$var" && return 100
if LC_ALL=C dpkg -l 'univention-mail-cyrus' 2>/dev/null | grep ^i 1>&2; then
echo -e "\tThe Cyrus integration package was found. Cyrus is not"
echo -e "\tsupported anymore by UCS 4.3. Aborting the upgrade. For instructions how to"
echo -e "\tproceed, please refer to https://help.univention.com/t/7957"
return 1
fi
}
# Bug #46605: Block if single-server SSO is configured
# The default sso nameserver entry is ucs-sso.$domainname
# If the configuration is different,
# https://help.univention.com/t/6681 was probably used.
# Default config in UCS 4.2 is done in univention-saml/91univention-saml.inst
update_check_reconfigured_sso () {
local var="update$VERSION/ignore_sso_domain"
ignore_check "$var" && return 100
if [ -n "$ucs_server_sso_fqdn" ] && [ "$ucs_server_sso_fqdn" != "ucs-sso.$domainname" ]; then
echo -e "\tSingle-Sign on was reconfigured and is not using the default"
echo -e "\tDNS settings. When continued, there will be issues using UMC"
echo -e "\tafter the update."
echo
echo -e "\tThis check can be disabled by setting the UCR variable"
echo -e "\tupdate43/ignore_sso_domain to yes."
return 1
fi
}
# Bug #46850: Block if failed.ldif exists
update_check_failed_ldif_exists() {
if [ -e /var/lib/univention-directory-replication/failed.ldif ]; then
echo "WARNING: A failed.ldif exists."
echo "Please check https://help.univention.com/t/what-to-do-if-a-failed-ldif-is-found/6432 for further information."
echo "The update can be started after the failed.ldif has been removed."
exit 1
fi
}
# Bug #46699
update_check_kopano_repo () {
local var="update$VERSION/ignore_kopano_repo"
ignore_check "$var" && return 100
for repo in kopano/repo/kopano-core kopano/repo/kopano-webapp kopano/repo/kopano-webmeetings; do
if is_ucr_true "$repo"; then
echo -e "\tAn external repository for the Kopano Apps is currently configured."
echo -e "\tThere are known issues when updating to UCS 4.3 and using software"
echo -e "\tfrom the Kopano software repository."
echo -e "\tThe update is blocked while Kopano and Univention are working"
echo -e "\ton a solution."
return 1
fi
done
}
# simulate 4.3 user migration, can be removed after 4.3-0
simulate_user_migration () {
python - <<'PYTHON'
import univention.admin.uldap
import sys
from univention.config_registry import ConfigRegistry
ucr = ConfigRegistry()
ucr.load()
lo, po = univention.admin.uldap.getAdminConnection()
default_user_filter = u'(&(|(&(objectClass=posixAccount)(objectClass=shadowAccount))(objectClass=univentionMail)(objectClass=sambaSamAccount)(objectClass=simpleSecurityObject)(objectClass=inetOrgPerson))(!(uidNumber=0))(!(uid=*$)))'
user_filter = ucr.get('update43/udm/migration/user/filter', default_user_filter)
ldap_only = 0
contact_only = 0
to_user = 0
for dn, user in lo.search(user_filter):
ocs = set(user['objectClass'])
has_posix = ocs & {'posixAccount', }
has_shadow = ocs & {'shadowAccount', }
has_samba = ocs & {'sambaSamAccount', }
has_kerberos = ocs & {'krb5Principal', 'krb5KDCEntry', }
has_mail = ocs & {'univentionMail', }
has_org_person = ocs & {'organizationalPerson', }
has_inet_org_person = ocs & {'inetOrgPerson', }
has_pki = ocs & {'pkiUser', }
has_ldap = ocs & {'simpleSecurityObject', 'uidObject'}
is_ldap_only = has_ldap and not any([has_posix, has_shadow, has_samba, has_kerberos, has_mail, has_org_person, has_inet_org_person, has_pki])
is_contact_only = has_inet_org_person and has_org_person and not any([has_posix, has_shadow, has_samba, has_kerberos, has_mail, has_ldap, has_pki])
ocs_to_add = {'posixAccount', 'shadowAccount', 'sambaSamAccount', 'krb5Principal', 'krb5KDCEntry', 'univentionMail', 'inetOrgPerson', 'organizationalPerson'} - ocs
if is_ldap_only:
sys.stderr.write('object {0} would be migrated to users/ldap object\n'.format(dn))
ldap_only += 1
elif is_contact_only:
sys.stderr.write('object {0} would be migrated to users/contact object\n'.format(dn))
contact_only += 1
elif ocs_to_add:
sys.stderr.write('object {0} would be migrated to a full users/user object\n'.format(dn))
to_user += 1
if ldap_only or contact_only or to_user:
print('\t{0} objects would be migrated to users/ldap objects'.format(ldap_only))
if contact_only:
print('\t{0} objects would be migrated to users/contact objects'.format(contact_only))
if to_user:
print('\t{0} objects would be migrated to full users/user objects'.format(to_user))
PYTHON
}
########
# 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
if [ "$server_role" = "domaincontroller_master" ]; then
echo
echo "Simulating 4.3 user migration ($(date)):"
echo
echo -e "\tAfter the upgrade to UCS 4.3 all existing user objects are migrated into a new \
LDAP format. This check simulates what would happen after the upgrade \
(which objects would be modified). \
Please check the $UPDATER_LOG for a complete list of objects." | fmt -u
echo
simulate_user_migration
fi
exit $RET