# -*- sh -*-
# This file can be included with #SCRIPTSCOMMON#
# ===== Dumping and reloading using LDIF files ========================= {{{
#
# If incompatible changes are done to the database underlying a LDAP
# directory we need to dump the contents and reload the data into a newly
# created database after the new server was installed. The following
# functions deal with this functionality.
# ----- Configuration of this component -------------------------------- {{{
#
# Dumping the database can have negative effects on the system we are
# running on. If there is a lot of data dumping it might fill a partition
# for example. Therefore we must give the user exact control over what we
# are doing.
database_dumping_enabled() { # {{{
# Check if the user has enabled database dumping for the current situation.
# Return success if yes.
# Usage: if database_dumping_enabled; then ... fi
db_get slapd/dump_database
case "$RET" in
always)
;;
"when needed")
database_format_changed || return 1
;;
never)
return 1
;;
*)
echo >&2 "Unknown value for slapd/dump_database: $RET"
echo >&2 "Please report!"
exit 1
;;
esac
}
# }}}
database_format_changed() { # {{{
# Check if the database format has changed since the old installed version
# Return success if yes.
# Usage: if database_format_changed; then
if dpkg --compare-versions "$OLD_VERSION" lt-nl 2.4.14; then
return 0
else
return 1
fi
}
# }}}
database_dumping_destdir() { # {{{
# Figure out the directory we are dumping the database to and create it
# if it does not exist.
# Usage: destdir=`database_dumping_destdir`
local dir
db_get slapd/dump_database_destdir
dir=`echo "$RET"|sed -e "s/VERSION/$OLD_VERSION/"`
mkdir -p -m 700 "$dir"
echo $dir
}
# }}}
create_new_user() { # {{{
if [ -z "`getent group openldap`" ]; then
addgroup --quiet --system openldap
fi
if [ -z "`getent passwd openldap`" ]; then
echo -n " Creating new user openldap... " >&2
adduser --quiet --system --home /nonexistent --shell /bin/false \
--ingroup openldap --disabled-password --disabled-login \
--no-create-home \
--gecos "OpenLDAP Server Account" openldap
echo "done." >&2
fi
}
# }}}
update_permissions() { # {{{
dir="$1"
[ -z "${SLAPD_USER}" ] || chown -R "${SLAPD_USER}" "${dir}"
[ -z "${SLAPD_GROUP}" ] || chgrp -R "${SLAPD_GROUP}" "${dir}"
chmod -R u=rwX,g=rX,o-rwx "${dir}"
}
# }}}
update_databases_permissions() { # {{{
for suffix in `get_suffix`; do
dbdir=`get_directory $suffix`
update_permissions "$dbdir"
done
}
# }}}
# }}}
# ----- Dumping and loading the data ------------------------------------ {{{
dump_databases() { # {{{
# If the user wants us to dump the databases they are dumped to the
# configured directory.
local db suffix file dir failed slapcat_opts
database_dumping_enabled || return 0
dir=`database_dumping_destdir`
echo >&2 " Dumping to $dir: "
for suffix in `get_suffix`; do
file="$dir/$suffix.ldif"
echo -n " - directory $suffix... " >&2
# Need to support slapd.d migration from preinst
if [ -f "${SLAPD_CONF}" ]; then
slapcat_opts="-f ${SLAPD_CONF}"
else
slapcat_opts="-F ${SLAPD_CONF}"
fi
slapcat ${slapcat_opts} -b "$suffix" > "$file" || failed=1
if [ "$failed" ]; then
rm -f "$file"
echo failed. >&2
exit 1
fi
echo "done." >&2
done
}
# }}}
load_databases() { # {{{
local dir file db dbdir backupdir
dir=`database_dumping_destdir`
echo >&2 " Loading from $dir: "
for suffix in `get_suffix`; do
dbdir=`get_directory $suffix`
if ! is_empty_dir "$dbdir"; then
echo >&2 \
" Directory $dbdir for $suffix not empty, aborting."
exit 1
fi
file="$dir/$suffix.ldif"
echo -n " - directory $suffix... " >&2
# If there is an old DB_CONFIG file, restore it before
# running slapadd
backupdir=`compute_backup_path -n "$dbdir" "$suffix"`
if [ -e "$backupdir"/DB_CONFIG ]; then
cp -a "$backupdir"/DB_CONFIG "$dbdir"/
else
copy_example_DB_CONFIG "$dbdir"/
fi
if [ -f "${SLAPD_CONF}" ]; then
slapadd_opts="-f ${SLAPD_CONF}"
else
slapadd_opts="-F ${SLAPD_CONF}"
fi
capture_diagnostics slapadd ${slapadd_opts} \
-q -b "$suffix" -l "$file" || failed=1
if [ "$failed" ]; then
rm -f "$dbdir"/*
echo failed. >&2
echo >&2
cat <<-EOF
Loading the database from the LDIF dump failed with the following
error while running slapadd:
EOF
release_diagnostics " "
exit 1
fi
echo "done." >&2
if [ -n "$SLAPD_USER" ] || [ -n "$SLAPD_GROUP" ]; then
echo -n " - chowning database directory ($SLAPD_USER:$SLAPD_GROUP)... "
[ -z "$SLAPD_USER" ] || \
chown -R "$SLAPD_USER" "$dbdir"
[ -z "$SLAPD_GROUP" ] || \
chgrp -R "$SLAPD_GROUP" "$dbdir"
echo "done";
fi
done
}
# }}}
move_incompatible_databases_away() { # {{{
echo >&2 " Moving old database directories to /var/backups:"
for suffix in `get_suffix`; do
dbdir=`get_directory $suffix`
move_old_database_away "$dbdir" "$suffix"
done
}
# }}}
# }}}
# {{{
# The following two functions need to support slapd.conf installations
# as long as upgrading from slapd.conf environment is supported.
# They're used to dump database in preinst which may have a slapd.conf file.
get_suffix() {
if [ -f "${SLAPD_CONF}" ]; then
for f in `get_all_slapd_conf_files`; do
grep '^suffix ' ${f} | sed 's/^suffix[[:space:]]\+\(.\+\)/\1/' | sed 's/"//g'
done
else
grep -h olcSuffix ${SLAPD_CONF}/cn\=config/olcDatabase* | cut -d: -f 2
fi
}
# }}}
get_directory() { # {{{
# Returns the db directory for a given suffix
if [ -d "${SLAPD_CONF}" ] && echo `get_suffix` | grep -q "$1" ; then
grep "olcDbDirectory:" `grep -l "olcSuffix: $1" ${SLAPD_CONF}/cn\=config/olcDatabase*` | cut -d: -f 2 | sed 's/^ *//g'
elif [ -f "${SLAPD_CONF}" ]; then
# Extract the directory for the given suffix ($1)
for f in `get_all_slapd_conf_files`; do
awk ' BEGIN { DB=0; SUF=""; DIR="" } ;
/^database/ { DB=1; SUF=""; DIR="" } ;
DB==1 && /^suffix[ \t]+"?'$1'"?$/ { SUF=$2 ; } ;
DB==1 && /^directory/ { DIR=$2 ;} ;
DB==1 && SUF!="" && DIR!="" { sub(/^"/,"",DIR) ; sub(/"$/,"",DIR) ; print DIR; SUF=""; DIR="" }' "${f}"
done
else
return 1
fi
}
# }}}
# Returns the list of all the config files: slapd.conf and included files.
get_all_slapd_conf_files() {
echo ${SLAPD_CONF}
awk '
BEGIN { I=0 }
/^include/ {
sub(/include/," ");
I=1;
}
I==1 && /^[ \t]+/ {
split($0,F) ;
for (f in F)
if (!match(F[f],/schema/)) {
print F[f]
} ;
next;
}
I==1 { I=0 }
' ${SLAPD_CONF}
}
# }}}
# }}}
compute_backup_path() { # {{{
# Compute the path to backup a database directory
# Usage: compute_backup_path [-n]
# XXX: should ask the user via debconf
local dirname basedn ok_exists
if [ "$1" = "-n" ]; then
ok_exists=yes
shift
fi
dirname="$1"
basedn="$2"
# Computing the name of the backup directory from the old version,
# the suffix etc. all makes me feel worried. I'd rather have a
# directory name which is not going to exist. So the simple
# scheme we are using now is to compute the filename from the
# directory name and appending date and time. And we check if it
# exists to be really sure... -- Torsten
local target
local id
id="$OLD_VERSION"
[ -n "$id" ] || id=`date +%Y%m%d-%H%M%S`
target="/var/backups/$basedn-$id.ldapdb"
# Configuration via dpkg-reconfigure.
# The backup directory already exists when reconfigured
# twice or more: append a timestamp.
if [ -e "${target}" ] && ([ "$MODE" = reconfigure ] || [ "$DEBCONF_RECONFIGURE" ]); then
target="$target-`date +%Y%m%d-%H%M%S`"
fi
if [ -e "$target" ] && [ -z "$ok_exists" ]; then
echo >&2
echo >&2 " Backup path $target exists. Giving up..."
exit 1
fi
echo "$target"
}
# }}}
move_old_database_away() { # {{{
# Move the old database away if it is still there
#
# In fact this function makes sure that the database directory is empty
# and can be populated with a new database. If something is in the way
# it is moved to a backup directory if the user accepted the debconf
# option slapd/move_old_database. Otherwise we output a warning and let
# the user fix it himself.
# Usage: move_old_database_away []
local databasedir backupdir
databasedir="$1"
suffix="${2:-unknown}"
if [ ! -e "$databasedir" ] || is_empty_dir "$databasedir"; then
return 0
fi
# Note that we can't just move the database dir as it might be
# a mount point. Instead me move the content which might
# include mount points as well anyway, but it's much less likely.
db_get slapd/move_old_database
if [ "$RET" = true ]; then
backupdir=`compute_backup_path "$databasedir" "$suffix"`
echo -n " - directory $suffix... " >&2
mkdir -p "$backupdir"
find "$databasedir" -mindepth 1 -maxdepth 1 \
-exec mv {} "$backupdir" \;
echo done. >&2
else
cat >&2 <
local directory srcdir
directory="$1"
srcdir="/usr/share/slapd"
if ! [ -f "${directory}/DB_CONFIG" ] && [ -d "$directory" ]; then
cp $srcdir/DB_CONFIG "${directory}/DB_CONFIG"
fi
}
# }}}
create_new_configuration() { # {{{
# Create a new configuration and directory
if [ ! -d /var/lib/ldap ]; then
mkdir /var/lib/ldap
fi
update_permissions /var/lib/ldap
if [ ! -d /var/run/slapd ]; then
mkdir /var/run/slapd
fi
update_permissions /var/run/slapd
# update_permissions doesn't allow a world readable dir.
# slapd run dir has the slapi socket and thus needs
# to be world accessible.
chmod 0755 /var/run/slapd
local init_ldif
init_ldif="/usr/share/slapd/slapd.init.ldif"
echo -n " Creating initial slapd configuration... " >&2
rm -rf "${SLAPD_CONF}"
mkdir "${SLAPD_CONF}"
capture_diagnostics slapadd -F "${SLAPD_CONF}" \
-b "cn=config" -l ${init_ldif} || failed=1
if [ "$failed" ]; then
cat <<-EOF
Loading the initial configuration from the ldif file (${init_ldif}) failed with the following
error while running slapadd:
EOF
release_diagnostics " "
exit 1
fi
update_permissions "${SLAPD_CONF}"
echo "done." >&2
}
# }}}
configure_v2_protocol_support() { # {{{
# Adds the "allow bind_v2" directive to the configuration if the user decided
# he wants to have ldap v2 enabled.
db_get slapd/allow_ldap_v2
if [ "$RET" != "true" ]; then return 0; fi
echo -n " Enabling LDAPv2 support... " >&2
if [ -d "$SLAPD_CONF" ]; then
if ! grep -q -E '^olcAllows:[[:space:]]+bind_v2' "${SLAPD_CONF}/cn=config.ldif"; then
echo "olcAllows: bind_v2" >> "${SLAPD_CONF}/cn=config.ldif"
fi
return 0
else
return 1
fi
echo . >&2
}
# }}}
backup_config_once() { # {{{
# Create a backup of the current configuration files.
# Usage: backup_config_once
local backupdir
if [ -z "$FLAG_CONFIG_BACKED_UP" ]; then
backupdir=`database_dumping_destdir`
if [ -e "$SLAPD_CONF" ]; then
cp -a "$SLAPD_CONF" "$backupdir"
fi
FLAG_CONFIG_BACKED_UP=yes
fi
}
# }}}
previous_version_older() { # {{{
# Check if the previous version is newer than the reference version passed.
# If we are not upgrading the previous version is assumed to be newer than
# any reference version.
# Usage: previous_version_older
if dpkg --compare-versions "$OLD_VERSION" lt-nl "$1"; then
return 0
else
return 1
fi
}
# }}}
previous_version_newer() { # {{{
# Check if the previous version is newer than the reference version passed.
# If we are not upgrading the previous version is assumed to be newer than
# any reference version.
# Usage: previous_version_newer
if dpkg --compare-versions "$OLD_VERSION" gt-nl "$1"; then
return 0
else
return 1
fi
} # }}}
upgrade_supported_from_backend() { # {{{
# Check if upgrading a database in the named backend is supported by
# our scripts.
# Usage: if upgrade_supported_from_backend "backend"; then ... fi
case "$1" in bdb|hdb) return 0; esac
return 1
}
# }}}
is_initial_configuration() { # {{{
# Check if this is the initial configuration and not an upgrade of an
# existing configuration
# Usage: if is_initial_configuration "$@"; then ... fi from top level
# Plain installation
if [ "$1" = configure ] && [ -z "$2" ]; then
return 0
fi
# Configuration via dpkg-reconfigure
if [ "$1" = reconfigure ] || [ "$DEBCONF_RECONFIGURE" ]; then
return 0
fi
# Upgrade but slapd.d doesn't exist. If the user is doing this
# intentionally because they want to put it somewhere else, they
# should select manual configuration in debconf.
if [ "$1" = configure ] && [ ! -e "$SLAPD_CONF" ]; then
return 0
fi
return 1
}
# }}}
is_empty_dir() { # {{{
# Check if a path refers to an empty directory
# Usage: if is_empty_dir "$dir"; then ... fi
output=`find "$1" -type d -maxdepth 0 -empty 2>/dev/null`
if [ "$output" ]; then
return 0
else
return 1
fi
}
# }}}
# ===== Global variables ================================================ {{{
#
# At some points we need to know which version we are upgrading from if
# any. More precisely we only care about the configuration and data we
# might have laying around. Some parts also want to know which mode the
# script is running in.
MODE="$1" # install, upgrade, etc. - see debian-policy
OLD_VERSION="$2"
# Source the init script configuration
# See example file debian/slapd.default for variables defined here
if [ -f "/etc/default/slapd" ]; then
. /etc/default/slapd
fi
# Load the default location of the slapd config file
if [ -z "$SLAPD_CONF" ]; then
if previous_version_older 2.4.11-0ubuntu1 \
&& [ -f "/etc/ldap/slapd.conf" ] \
&& [ ! -e "/etc/ldap/slapd.d" ] ; then
SLAPD_CONF="/etc/ldap/slapd.conf"
else
SLAPD_CONF="/etc/ldap/slapd.d/"
fi
fi
# }}}
# ----- Handling diagnostic output ------------------------------------ {{{
#
# Often you want to run a program while you are showing progress
# information to the user. If the program you are running outputs some
# diagnostics it will mess up your screen.
#
# This is what the following functions are designed for. When running the
# program, use capture_diagnostics to store what the program outputs to
# stderr and use release_diagnostics to write out the captured output.
capture_diagnostics() { # {{{
# Run the command passed and capture the diagnostic output in a temporary
# file. You can dump that file using release_diagnostics.
# Create the temporary file
local tmpfile
tmpfile=`mktemp`
exec 7<>"$tmpfile"
rm "$tmpfile"
# Run the program and capture stderr. If the program fails the
# function fails with the same status.
"$@" 2>&7 || return $?
}
# }}}
release_diagnostics() { # {{{
# Dump the diagnostic output captured via capture_diagnostics, optionally
# prefixing each line.
# Usage: release_diagnostics "prefix"
local script
script='
seek STDIN, 0, 0;
print "$ARGV[0]$_" while ();';
perl -e "$script" "$1" <&7
}
# }}}
# }}}
# vim: set sw=8 foldmethod=marker: