# -*- 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: