#!/bin/sh
##
## LDAP: Compare DITs in two LDAP servers
##
## Copyright (c) 2006-2007 SATOH Fumiyasu @ OSS Technology, Japan
##                         <http://www.osstech.co.jp/>
##
## Date: 2006-06-05, since 2006-06-05
##
## Required external commands:
##	ldapsearch - OpenLDAP
##	ldifdiff - See below
##		http://people.valinux.co.jp/~taru/d/?date=20041030
##		http://cvs.sourceforge.jp/cgi-bin/viewcvs.cgi/ultrapossum/utils/misc/ldifdiff/ldifdiff?rev=HEAD&content-type=text/vnd.viewcvs-markup
##

set -u

## Functions
## ======================================================================

warn()
{
    echo "$0: warning: $1" 1>&2
}

err()
{
    echo "$0: error: $1" 1>&2
}

die()
{
    err "$1"
    exit ${2:-1}
}

## Options
## ======================================================================

cmd_tmp_base="/tmp/ldap-diff.tmp.XXXXXX"

ldap_base=""

master_uri=""
master_bind_dn=""
master_bind_secret=""

slave_uri=""
slave_bind_dn=""
slave_bind_secret=""

flag_verbose=""

cmd_usage="Usage: $0 [OPTIONS]

Options [default]:
 -b, --base, --base-uri BASE
    Base DN
 -H, -H1, --master-uri URI
    LDAP URI for master server
 -D, -D1, --master-bind-dn DN
    Bind DN for master server
 -y, -y1, --master-bind-secret FILE
    Password file for master server
 -H2, --slave-uri URI
    LDAP URI for slave server
 -D2, --slave-bind-dn DN
    Bind DN for slave server [same as master]
 -y2, --slave-bind-secret FILE
    Password file for slave server [same as master]
"

## Parse command-line options
## ----------------------------------------------------------------------

getopts_want_arg()
{
    if [ "$2" -eq 0 ]; then
	die "option requires an argument: $1"
    fi
}

while test "$#" -gt 0; do
    opt="$1"; shift
    test x"$opt" = x"--" && break
    case "$opt" in
    --help)
	echo "$cmd_usage"
	exit 0
	;;
    -v|--verbose)
	flag_verbose="yes"
	;;
    -b|--base|--ldap-base)
	getopts_want_arg "$opt" "$#"
	ldap_base="$1"; shift
	;;
    -H|-H1|--master-uri)
	getopts_want_arg "$opt" "$#"
	master_uri="$1"; shift
	;;
    -D|-D1|--master-bind-dn)
	getopts_want_arg "$opt" "$#"
	master_bind_dn="$1"; shift
	;;
    -y|-y1|--master-bind-secret)
	getopts_want_arg "$opt" "$#"
	master_bind_secret="$1"; shift
	;;
    -H2|--slave-uri)
	getopts_want_arg "$opt" "$#"
	slave_uri="$1"; shift
	;;
    -D2|--slave-bind-dn)
	getopts_want_arg "$opt" "$#"
	slave_bind_dn="$1"; shift
	;;
    -y2|--slave-bind-secret)
	getopts_want_arg "$opt" "$#"
	slave_bind_secret="$1"; shift
	;;
    -*)
	die "illegal option: $opt"
	;;
    *)
	set -- "$opt" "$@"
	break
	;;
    esac
done

if [ -z "$slave_uri" ]; then
    die "--slave-uri option required"
fi

if [ -z "$slave_bind_dn" ]; then
    slave_bind_dn="$master_bind_dn"
fi
if [ -z "$slave_bind_secret" ]; then
    slave_bind_secret="$master_bind_secret"
fi

## Main
## ======================================================================

## Retrieve LDAP data from master server
master_ldif_tmp="`mktemp "$cmd_tmp_base"`" || die "cannot create a temporary file"
exec 3<"$master_ldif_tmp"
exec 4>"$master_ldif_tmp"
rm "$master_ldif_tmp"

ldapsearch \
    -l 0 -z 0 -LLL \
    -H "$master_uri" \
    -x -D "$master_bind_dn" ${master_bind_secret:+-y "$master_bind_secret"} \
    ${ldap_base:+-b "$ldap_base"} \
    -s sub \
>/dev/fd/4 \
|| die "ldapsearch on master server failed"

## Retrieve LDAP data from slave server
slave_ldif_tmp="`mktemp "$cmd_tmp_base"`" || die "cannot create a temporary file"
exec 5<"$slave_ldif_tmp"
exec 6>"$slave_ldif_tmp"
rm "$slave_ldif_tmp"

ldapsearch \
    -l 0 -z 0 -LLL \
    -H "$slave_uri" \
    -x -D "$slave_bind_dn" ${slave_bind_secret:+-y "$slave_bind_secret"} \
    -b "$ldap_base" \
    -s sub \
>/dev/fd/6 \
|| die "ldapsearch on slave server failed"

ldifdiff /dev/fd/3 /dev/fd/5 || die "ldifdiff failed"

