#!/usr/local/bin/perl -w
##############################################################################
# $Id: ldapedit,v 1.2 2002/02/22 00:42:34 jheiss Exp $
##############################################################################
# Bring up an LDAP entry in $EDITOR and allow the user to edit it.
# When the user exits the editor, save the changes back to LDAP.
#
# Note that this tool only allows you to add/change/delete attributes
# for an existing entry.  It does not allow you to add/change/delete
# entries themselves.  Use the ldapadd/ldapmodrn/ldapdelete tools
# supplied with the LDAP server for that.
#
# TODO:
# - Allow user to specify options to ldapsearch, like -x
# - Allow an environment variable for path to ldiff
# - Add the option of using Net::LDAP instead of the command-line tools
##############################################################################
# $Log: ldapedit,v $
# Revision 1.2  2002/02/22 00:42:34  jheiss
# Use /usr/local/bin/perl -w
#
# Revision 1.1  2002/02/09 03:25:10  jheiss
# Initial revision
#
##############################################################################

# Includes and such
use POSIX;

# Constants

# Globals
my %old;
my %new;

sub usage
{
	print STDERR "Usage: $0 <filter>\n";
	print STDERR "For example: $0 uid=bob\n";
	print STDERR "             $0 cn=mygroup\n";
	exit(1);
}

if (scalar @ARGV == 0)
{
	usage();
}

my %entries;
my $entry;
my @elements;

open(LS, "ldapsearch -LLL $ARGV[0] |") || die "Failed to fork ldapsearch\n";
#open(LS, "ldapsearch -LLL -x $ARGV[0] |") || die "Failed to fork ldapsearch\n";
my @results = <LS>;
close(LS) || die "ldapsearch exitted with error\n";

# Amazingly, Perl doesn't seem to have a clean mkstemp implementation...
# This came from a Tom Christiansen email I found via a Google search for
# perl and mkstemp.
my $origfile;
do
{ 
	$origfile = tmpnam();
} until sysopen(OF, $origfile, O_RDWR|O_CREAT|O_EXCL, 0666);
my $newfile;
do
{ 
	$newfile = tmpnam();
} until sysopen(NF, $newfile, O_RDWR|O_CREAT|O_EXCL, 0666);

$SIG{INT} = cleanup;

print OF @results;
close(OF);
print NF @results;
close(NF);

if ($ENV{'EDITOR'})
{
	system("$ENV{'EDITOR'} $newfile");
}
else
{
	system("vi $newfile");
}

# Assume ldiff is in the same directory as we are
$0 =~ m,(/?(.*/)*),;
my $dirname = $1;

open(LDIFF, "$dirname/ldiff $origfile $newfile |") ||
	cleanup("Failed to fork ldiff\n");
my @diff = <LDIFF>;
close(LDIFF) || cleanup("ldiff exitted with error\n");

# Check to see if the user changed anything
if (join('', @diff) eq '')
{
	cleanup("No changes made\n");
}

print "\nConfirm your changes:\n\n";
print @diff;
print "Continue [y/N]: ";
chomp(my $input = <STDIN>);
if ($input ne 'y' && $input ne 'Y')
{
	cleanup("User canceled\n");
}

# ldapmodify will exit without any command line options.  We don't really
# need any, specifying LDAPv3 seems fairly innocuous.
$SIG{PIPE} = 'IGNORE';  # Recommended by the perlipc man page
open(LM, "| ldapmodify -P 3") || cleanup("Failed to fork ldapmodify\n");
print LM @diff;
close(LM) || cleanup("ldapmodify exitted with error\n");

cleanup();

sub cleanup
{
	my $message = shift;

	print STDERR $message if ($message);

	print STDERR "Cleaning up\n";
	unlink($origfile);
	unlink($newfile);

	exit(1) if ($message);
	exit(0);
}

