Blob Blame History Raw
#!/bin/bash
# This script serves one purpose, to add a possibly missing attribute
# to a ppolicy schema in a dynamic configuration of OpenLDAP. This
# attribute was introduced in openldap-2.4.43 and slapd will not 
# start without it later on.
#
# The script tries to update in a directory given as first parameter,
# or in /etc/openldap/slapd.d implicitly.
#
# Author: Matus Honek <mhonek@redhat.com>
# Bugzilla: #1487857

function log {
    echo "Update dynamic configuration: " $@
    true
}

function iferr {
    if [ $? -ne 0 ]; then
	log "ERROR: " $@
	true
    else
	false
    fi
}

function update {
    set -u
    shopt -s extglob

    ORIGINAL="${1:-/etc/openldap/slapd.d}"
    ORIGINAL="${ORIGINAL%*(/)}"

    ### check if necessary
    grep -r "pwdMaxRecordedFail" "${ORIGINAL}/cn=config/cn=schema" >/dev/null
    [ $? -eq 0 ] && log "Schemas look up to date. Ok. Quitting." && return 0

    ### prep
    log "Prepare environment."
    
    TEMPDIR=$(mktemp -d)
    iferr "Could not create a temporary directory. Quitting." && return 1
    DBDIR="${TEMPDIR}/db"
    SUBDBDIR="${DBDIR}/cn=temporary"

    mkdir "${DBDIR}"
    iferr "Could not create temporary configuration directory. Quitting." && return 1
    cp -r --no-target-directory "${ORIGINAL}" "${SUBDBDIR}"
    iferr "Could not copy configuration. Quitting." && return 1
    
    pushd "$TEMPDIR" >/dev/null

    cat > temp.conf <<EOF
database ldif
suffix cn=temporary
directory db
access to * by * manage
EOF
    
    SOCKET="$(pwd)/socket"
    LISTENER="ldapi://${SOCKET//\//%2F}"
    CONN_PARAMS=("-Y" "EXTERNAL" "-H" "${LISTENER}")
    
    slapd -f temp.conf -h "$LISTENER" -d 0 >/dev/null 2>&1 &
    SLAPDPID="$!"
    sleep 2

    ldapadd ${CONN_PARAMS[@]} -d 0 >/dev/null 2>&1 <<EOF
dn: cn=temporary
objectClass: olcGlobal
cn: temporary
EOF
    iferr "Could not populate the temporary database. Quitting." && return 1
    
    ### update
    log "Update with new pwdMaxRecordedFailure attribute."
    FILTER="(&"
    FILTER+="(olcObjectClasses=*'pwdPolicy'*)"
    FILTER+="(!(olcObjectClasses=*'pwdPolicy'*'pwdMaxRecordedFailure'*))"
    FILTER+="(!(olcAttributeTypes=*'pwdMaxRecordedFailure'*))"
    FILTER+=")"
    RES=$(ldapsearch ${CONN_PARAMS[@]} \
		     -b cn=schema,cn=config,cn=temporary \
		     -LLL \
		     -o ldif-wrap=no \
		     "$FILTER" \
		     dn olcObjectClasses \
		     2>/dev/null \
	      | sed '/^$/d')
    DN=$(printf "$RES" | grep '^dn:')
    OC=$(printf "$RES" | grep "^olcObjectClasses:.*'pwdPolicy'")
    NEWOC="${OC//$ pwdSafeModify /$ pwdSafeModify $ pwdMaxRecordedFailure }"

    test $(echo "$DN" | wc -l) = 1
    iferr "Received more than one DN. Cannot continue. Quitting." && return 1
    test "$NEWOC" != "$OC"
    iferr "Updating pwdPolicy objectClass definition failed. Quitting." && return 1

    ldapmodify ${CONN_PARAMS[@]} -d 0 >/dev/null 2>&1 <<EOF
$DN
changetype: modify
add: olcAttributeTypes
olcAttributeTypes: ( 1.3.6.1.4.1.42.2.27.8.1.30 NAME 'pwdMaxRecordedFailur
 e' EQUALITY integerMatch ORDERING integerOrderingMatch  SYNTAX 1.3.6.1.4.1.
 1466.115.121.1.27 SINGLE-VALUE )
-
delete: olcObjectClasses
$OC
-
add: olcObjectClasses
$NEWOC
EOF
    iferr "Updating with new attribute failed. Quitting." && return 1

    popd >/dev/null

    ### apply
    log "Apply changes."
    cp -r --no-target-directory "$ORIGINAL" "$ORIGINAL~backup"
    iferr "Backing up old configuration failed. Quitting." && return 1
    cp -r --no-target-directory "$SUBDBDIR" "$ORIGINAL"
    iferr "Applying new configuration failed. Quitting." && return 1
    
    ### clean up
    log "Clean up."
    kill "$SLAPDPID"
    SLAPDPID=
    rm -rf "$TEMPDIR"
    TEMPDIR=
}

SLAPDPID=
TEMPDIR=
update "$1"
if [ $? -ne 0 ]; then
    log "Clean up."
    echo "$SLAPDPID"
    echo "$TEMPDIR"
    kill "$SLAPDPID"
    rm -rf "$TEMPDIR"
fi
log "Finished."