#!/bin/sh -f

. shell-config
. shell-error
. shell-quote

rdelim='[[:space:]]\+'
wdelim=' '

MAIN_SLAPD_CONF="/etc/openldap/slapd.conf"

# local functions

read_config()
{
    shell_config_get "$1" "$2" "$rdelim" 
}

get_config()
{
    egrep -i "^include[[:space:]].+slapd-.+\.conf[[:space:]]*$" "$MAIN_SLAPD_CONF"|cut -f2 -d ' '
}

get_slapd_status()
{
    local rc=1

    [ ! -e "/etc/init.d/slapd" ] && message "No such file /etc/init.d/slapd" && return $rc

    /etc/init.d/slapd status|grep -q running >/dev/null 2>&1
    rc=$?

    return $rc
}

to_upper()
{
    local name="$1"

    echo "$name"|tr '[[:lower:]]' '[[:upper:]]'
}

print_info()
{
    local conf_file="$1" ; shift
    local suffix=

    [ -z "$conf_file" ] && message "conf_file not set"
    [ ! -e "$conf_file" ] && message "$conf_file file not found" && return

    suffix="$(read_config "$conf_file" suffix |tr -d '"')"
    [ -n "$suffix" ] && echo "$suffix $conf_file"
}

check_dn_name()
{
    local name="$1" ; shift
    local rc=

    echo "$name"|egrep -qi "^dc=[a-z][a-z0-9]+(,dc=[a-z][a-z0-9]+)*$"
    rc=$?
    [ $rc -eq 1 ] && message "invalid suffix dn '$name'" && return $rc
    
    set +f ; egrep -q "^suffix[[:space:]]+\"?$name\"?$" /etc/openldap/slapd-*.conf; rc=$?  ; set -f
    [ $rc -eq 0 ] && message "DN '$name' already exists" && return 1

    get_slapd_status
    rc=$?
    [ $rc -eq 1 ] && message "Slapd isn't running" && return $rc 

    return $rc

}

dn_2_host()
{
    local dn="$1"
    local host=

    echo "$dn"|sed -e 's/^dc=//i'|sed -e 's/,dc=/\./g'
}

# global functions
get_local_dn()
{
    local dn=""

    [ "$#" -ge 1 ] && dn="$1" && shift

    [ -e "$MAIN_SLAPD_CONF" ] || message "$MAIN_SLAPD_CONF file not found" 

    for conf in $(get_config) ;do
        if [ -z "$dn" ] 
        then
            print_info "$conf"
        else
            print_info "$conf"|egrep -w "^$dn[[:space:]]"|cut -f2 -d' ' 
        fi
    done

}

create_dn()
{
    local dn="$1"
    local dn_to_host=$(dn_2_host "$dn")
    local realm=$(dn_2_host "$dn"); realm="$(to_upper "$realm")"
    local basedir=${MAIN_SLAPD_CONF%/*}	
    local template="$basedir/slapd-template.conf"
    local new_dn_conf="$basedir/slapd-$dn_to_host.conf"
    local passwd=$(pwgen -n 16 -1)

    #copy template into slapd-dn_to_host.conf
    cp "$template" "$new_dn_conf"
    chmod 640 "$new_dn_conf"
    chown root:ldap "$new_dn_conf"

    #fix dc=. base, password
    sed -i -e "s/dc=template/$dn/g" $new_dn_conf
    sed -i -e "s/template/$dn_to_host/g" $new_dn_conf
    sed -i -e "s/REALM/$realm/g" $new_dn_conf
    sed -i -e "s/secret/$passwd/g" $new_dn_conf

    echo "include $new_dn_conf" >>  "$MAIN_SLAPD_CONF"

    ldap-init "$new_dn_conf" 

    /etc/init.d/slapd condrestart >/dev/null   
}

delete_dn()
{
    local dn="$1"
    local dn_to_host=$(dn_2_host "$dn")
    local basedir="${MAIN_SLAPD_CONF%/*}"
    local dn_conf="$(get_local_dn "$dn")"
    local dn_base_file="$(read_config "$dn_conf" directory)"

    if [ ! -f "$dn_conf" ] ;then
        message "No such DN '$dn'" 
        exit 1
    fi

    rm -f "$dn_conf"
    rm -rf "$dn_base_file"
    dn_conf="$(quote_sed_regexp $dn_conf)"
    sed -r -i -e "/^include[[:space:]]+$dn_conf$/ d" "$MAIN_SLAPD_CONF"

    /etc/init.d/slapd condrestart >/dev/null 2>&1

}

rename_dn()
{
    local old="$1" ; shift
    local new="$1" ; shift
    local oldhost="$(dn_2_host "$old")"
    local newhost="$(dn_2_host "$new")"
    local databasedir=""
    local oldname=""
    local newname=""


    TMPFILE="$(mktemp -t "$oldhost.XXXXXXXXXX")" || fatal "can't create tempfile"
   
    #slapcating old database
    /etc/init.d/slapd stop && slapcat -b "$old" -l "$TMPFILE"
   
    #substitution dc=old to dc=new
    sed -r -i -e "s/$(quote_sed_regexp $old)/$(quote_sed_regexp $new)/g" "$TMPFILE"
    # changing 'dc: '
    oldname="$(quote_sed_regexp "$(echo "$oldhost"|cut -f1 -d'.')")"
    newname="$(quote_sed_regexp "$(echo "$newhost"|cut -f1 -d'.')")"
    sed -r -i -e "s/dc:[[:space:]]$oldname/dc: $newname/" "$TMPFILE"

    #substitution cn=OLDDOMAIN to cn=NEWDOMAIN (KDC)
    oldname="$(to_upper $oldhost)"
    newname="$(to_upper $newhost)"
    sed -r -i -e "s/cn=$oldname/cn=$newname/g" "$TMPFILE"
    #substitution @OLDDOMAIN to @NEWDOMAIN (KDC)
    sed -r -i -e "s/@$oldname/@$newname/g" "$TMPFILE"

    #substitution olddomain to newdomain
    sed -r -i -e "s/$oldhost/$newhost/g" "$TMPFILE"
   
    #fixing main slapd conf
    sed -r -i -e "s/^include[[:space:]]+$(quote_sed_regexp "/etc/openldap/slapd-$oldhost.conf")$/include $(quote_sed_regexp "/etc/openldap/slapd-$newhost.conf")/" "$MAIN_SLAPD_CONF"

    #moving old to new
    mv "/etc/openldap/slapd-$oldhost.conf" "/etc/openldap/slapd-$newhost.conf"
   
    #changing dc=old to dc=new
    sed -r -i -e "s/$(quote_sed_regexp $old)/$(quote_sed_regexp $new)/g" "/etc/openldap/slapd-$newhost.conf"
   
    #database dir with OLD directory value
    databasedir="$(read_config "/etc/openldap/slapd-$newhost.conf" directory)"
   
    #removing old database dir with database
    rm -rf "$databasedir" || fatal "can't remove old database dir"
   
    #changing directory value
    sed -r -i -e "s/^directory[[:space:]].+/directory $(quote_sed_regexp "/var/lib/ldap/bases/$newhost")/" "/etc/openldap/slapd-$newhost.conf" 
   
    #database dir with NEW directory value
    databasedir="$(read_config "/etc/openldap/slapd-$newhost.conf" directory)"
   
    #adding changed ldif
    mkdir -p "$databasedir"
    chmod 700 "$databasedir"
    slapadd -c -b "$new" -l "$TMPFILE"
    chown -R ldap:ldap "$databasedir"
   
    /etc/init.d/slapd start
    rm -f "$TMPFILE" >&2
}

action="$1" ; shift
[ $# -eq 1 ] && object="$1" && shift
[ $# -eq 2 ] && old="$1" && new="$2"


case $action in
    get)
    ;;
    getlocal)
        get_local_dn
    ;;
    create)
        [ -z "$object" ] && fatal "object not set" 
        check_dn_name $object || exit 1
        create_dn $object
    ;;
    set)
    ;;
    setlocal)
    ;;
    delete)
        [ -z "$object" ] && fatal "object not set" 
        delete_dn $object	
    ;;
    find)
        [ -z "$object" ] && fatal "object not set"
        c_file="$(get_local_dn "$object")"

        [ -f "$c_file" ] && echo "$c_file"
    ;;
    rename)
        [ -z "$old" -o -z "$new" ] && fatal "old domain or new domain not set" 
        rename_dn "$old" "$new"
    ;;
    *)
    echo "$0 action [object|olddomain newdomain]"
    ;;
esac


